cookidoo-shopping-advanced/src/CookidooScraper.php

97 lines
4.0 KiB
PHP

<?php
namespace CookidooShoppingAdvanced;
use CookidooShoppingAdvanced\Models\Category;
use CookidooShoppingAdvanced\Models\Ingredient;
use CookidooShoppingAdvanced\Models\ShoppingList;
use Exception;
use Goutte\Client;
use Symfony\Component\HttpClient\HttpClient;
class CookidooScraper
{
private const PAGE_LOGIN = 'https://cookidoo.de/profile/de-DE/login?redirectAfterLogin=%2Ffoundation%2Fde-DE';
private const PAGE_LOGIN_BUTTON_ID = 'j_submit_id';
private const PAGE_LOGIN_FIELD_USER = 'j_username';
private const PAGE_LOGIN_FIELD_PASSWORD = 'j_password';
private const PAGE_SHOPPING_LIST = 'https://cookidoo.de/shopping/de-DE';
private const PAGE_SHOPPING_LIST_GROUP_TAG = 'pm-check-group';
private const PAGE_SHOPPING_LIST_GROUP_HEADLINE = 'h4.pm-check-group__title';
private const PAGE_SHOPPING_LIST_GROUP_INGREDIENT = 'li.pm-check-group__list-item';
private const PAGE_SHOPPING_LIST_GROUP_INGREDIENT_LABEL = 'span[data-type=ingredientNotation]';
private const PAGE_SHOPPING_LIST_GROUP_INGREDIENT_AMOUNT = 'span[data-type=value]';
private const PAGE_SHOPPING_LIST_GROUP_INGREDIENT_UNIT = 'span[data-type=unitNotation]';
private const USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:87.0) Gecko/20100101 Firefox/87.0';
private Client $client;
private bool $login = false;
public function __construct() {
$this->client = new Client(HttpClient::create(['headers' => [
'user-agent' => self::USER_AGENT,
'accept' => "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
'accept-language' => "de,en-US;q=0.7,en;q=0.3",
], 'timeout' => 60]));
}
public function login(string $user, string $password): void {
try {
$crawler = $this->client->request('GET', self::PAGE_LOGIN);
$form = $crawler->selectButton(self::PAGE_LOGIN_BUTTON_ID)->form();
$submitResult = $this->client->submit($form, [
self::PAGE_LOGIN_FIELD_USER => $user,
self::PAGE_LOGIN_FIELD_PASSWORD => $password
]);
if (stripos($submitResult->getUri(), 'authentication_error=true') !== false) {
throw new Exception("Authentication error");
}
$this->login = true;
} catch (Exception $e) {
throw new Exception(sprintf("Cannot login: %s", $e->getMessage()));
}
}
public function getShopptingList(): ShoppingList {
if (!$this->login) {
throw new Exception('You need to login first.');
}
$crawler = $this->client->request('GET', self::PAGE_SHOPPING_LIST);
$crawler = $crawler->filter(self::PAGE_SHOPPING_LIST_GROUP_TAG);
$shoppingList = new ShoppingList();
$crawler->each(function ($parentCrawler) use($shoppingList) {
if (empty($parentCrawler->text(''))) {
return;
}
$headline = $parentCrawler->filter(self::PAGE_SHOPPING_LIST_GROUP_HEADLINE);
if (empty($headline->text(''))) {
return;
}
$category = new Category($headline->text());
$ingredients = $parentCrawler->filter(self::PAGE_SHOPPING_LIST_GROUP_INGREDIENT);
$ingredients->each(function ($ingredient) use($shoppingList, $category) {
$ingredient = new Ingredient(
$category,
$ingredient->filter(self::PAGE_SHOPPING_LIST_GROUP_INGREDIENT_LABEL)->text(''),
$ingredient->filter(self::PAGE_SHOPPING_LIST_GROUP_INGREDIENT_AMOUNT)->text(0),
$ingredient->filter(self::PAGE_SHOPPING_LIST_GROUP_INGREDIENT_UNIT)->text(''),
);
if (!$ingredient->isValid()) {
throw new \Exception("Invalid ingredient: $ingredient");
}
$shoppingList->add($ingredient);
});
});
return $shoppingList;
}
}