Last active
February 19, 2020 20:59
-
-
Save shtrih/171a5383cbf0220bd71cee6b6a1fc755 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Created by PhpStorm. | |
* User: shtrih | |
* Date: 24.09.2017 | |
* Time: 21:57 | |
*/ | |
namespace App\Util; | |
use Illuminate\Contracts\Filesystem\FileNotFoundException; | |
trait Csv | |
{ | |
/** | |
* @param \Iterator|array $rows | |
* @param $filepath | |
* @param callable|null $rowPreSaveCallback Row as argument | |
*/ | |
public function saveCSV($rows, $filepath, callable $rowPreSaveCallback = null) | |
{ | |
/** | |
* @var \Illuminate\Console\OutputStyle $this->output | |
*/ | |
$progressbar = $this->output->createProgressBar(count($rows)); | |
$file = fopen($filepath, 'w'); | |
foreach ($rows as $row) { | |
if ($rowPreSaveCallback) { | |
$row = call_user_func($rowPreSaveCallback, $row); | |
if (!empty($row['rows'])) { | |
foreach ($row['rows'] as $r) { | |
fputcsv($file, $r); | |
} | |
continue; | |
} | |
} | |
fputcsv($file, $row); | |
$progressbar->advance(); | |
} | |
fclose($file); | |
$progressbar->finish(); | |
} | |
public function readCSV($filename) | |
{ | |
$result = []; | |
$h = fopen($filename, 'r'); | |
if (false === $h) { | |
throw new FileNotFoundException(); | |
} | |
while (($row = fgetcsv($h)) !== false) { | |
$result[] = $row; | |
} | |
return $result; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Console\Commands; | |
use App\Util\Csv; | |
use GuzzleHttp\Client; | |
use Illuminate\Console\Command; | |
class GrabGameList extends Command | |
{ | |
use Csv; | |
/** | |
* The name and signature of the console command. | |
* | |
* @var string | |
*/ | |
protected $signature = 'steam:game-list'; | |
/** | |
* The console command description. | |
* | |
* @var string | |
*/ | |
protected $description = 'Получаем список игр с https://steamdb.info/sales/?max_price=25&min_discount=0&min_rating=0&displayOnly=Game&category=29'; | |
/** | |
* @var Client | |
*/ | |
private $webClient; | |
/** | |
* Create a new command instance. | |
* | |
* @param Client $webClient | |
*/ | |
public function __construct(Client $webClient) | |
{ | |
parent::__construct(); | |
$this->webClient = $webClient; | |
} | |
/** | |
* Execute the console command. | |
* | |
* @return mixed | |
*/ | |
public function handle() | |
{ | |
$this->info('Fetching games'); | |
$fromCache = true; | |
$html = \Cache::remember('games-list', 30, function () use (&$fromCache) { | |
$fromCache = false; | |
$response = $this->webClient->get('https://steamdb.info/sales/', ['query' => [ | |
'max_price' => 25, | |
'min_discount' => 0, | |
'min_rating' => 0, | |
'displayOnly' => 'Game', | |
'category' => 29, | |
'cc' => 'ru', | |
]]); | |
return $response->getBody()->getContents(); | |
}); | |
$this->info(sprintf('Fetched from %s', $fromCache ? 'cache' : 'host')); | |
// dd($html); | |
$query = htmlqp($html, 'table > tbody', ['convert_to_encoding' => 'utf-8']) | |
->find('tr') | |
->sort(function (\DOMNode $a, \DOMNode $b) { | |
$a = qp($a)->find('td:nth(5)')->attr('data-sort'); | |
$b = qp($b)->find('td:nth(5)')->attr('data-sort'); | |
if ($a === $b) | |
return 0; | |
return $a > $b ? 1 : -1; | |
}, true); | |
$file = storage_path('app\games-list.csv'); | |
$this->saveCSV($query, $file, function ($row) { | |
return [$row->attr('data-appid'), $row->find('td:nth(3) a')->text(), $row->find('td:nth(5)')->text()]; | |
}); | |
$this->info(''); | |
$this->info('Saved to csv into ' . $file); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Console\Commands; | |
use App\Util\Csv; | |
use GuzzleHttp\Client; | |
use Illuminate\Console\Command; | |
class GrabItemsByGame extends Command | |
{ | |
use Csv; | |
/** | |
* The name and signature of the console command. | |
* | |
* @var string | |
*/ | |
protected $signature = 'steam:items-list'; | |
/** | |
* The console command description. | |
* | |
* @var string | |
*/ | |
protected $description = 'Command description'; | |
/** | |
* @var Client | |
*/ | |
private $webClient; | |
/** | |
* Create a new command instance. | |
* | |
* @param Client $webClient | |
*/ | |
public function __construct(Client $webClient) | |
{ | |
parent::__construct(); | |
$this->webClient = $webClient; | |
} | |
/** | |
* Execute the console command. | |
* | |
* @return mixed | |
*/ | |
public function handle() | |
{ | |
$gamesList = $this->readCSV(storage_path('app\games-list.csv')); | |
$this->output->progressStart(count($gamesList)); | |
foreach ($gamesList as &$game) { | |
list($appid, $name) = $game; | |
if (!$name) { | |
$this->warn('Empty game name. Skipping.'); | |
continue; | |
} | |
$sleep = 29 + mt_rand(10,23); | |
$this->info(sprintf('Fetching «%s», sleep %d.', $name, $sleep)); | |
$cacheKey = 'game-items-' . $appid; | |
$item = \Cache::get($cacheKey); | |
$cached = true; | |
if (!$item) { | |
$cached = false; | |
sleep($sleep); | |
// http://steamcommunity.com/market/search/render/?query=Masked%20Shooters%202&start=0&count=50&search_descriptions=0&sort_column=price&sort_dir=desc | |
// appid=753&category_753_Game%5B%5D=tag_app_585690 | |
$response = $this->webClient->get('http://steamcommunity.com/market/search/render/', [ | |
'query' => [ | |
// 'query' => $name, | |
'start' => 0, | |
'count' => 50, | |
'search_descriptions' => 0, | |
'sort_column' => 'price', | |
'sort_dir' => 'desc', | |
'appid' => 753, | |
'category_753_Game[]' => 'tag_app_' . $appid | |
], | |
'headers' => [ | |
'Accept-Language' => 'en-US;q=0.8,en;q=0.6', | |
], | |
'cookie' => [ | |
'steamCountry' => 'RU%7C67b95f7bc66bd19244aab3e0c8e93d89' | |
] | |
]); | |
$item = \GuzzleHttp\json_decode($response->getBody()->getContents(), true); | |
$cacheTime = 60 * 12; | |
if (empty($item['success'])) { | |
$cacheTime = 30; | |
$this->warn('Failed to get items: ' . $response->getReasonPhrase()); | |
} | |
\Cache::put($cacheKey, $item, $cacheTime); | |
} | |
$game['items-html'] = $item['results_html']; | |
$this->output->progressAdvance(); | |
} | |
$this->output->progressFinish(); | |
libxml_use_internal_errors(true); // issues with clone nodes with id attr | |
$this->saveCSV($gamesList, storage_path('app\games-items-list.csv'), function ($row) { | |
if (!empty($row['items-html'])) { | |
$items = []; | |
$query = htmlqp($row['items-html'], '.market_listing_row', ['convert_to_encoding' => 'utf-8']); | |
foreach ($query as $item) { | |
$items[] = ['', $item->find('span.market_listing_item_name')->text(), $item->find('span.normal_price > .normal_price')->text()]; | |
} | |
unset($row['items-html']); | |
array_unshift($items, $row); | |
return [ | |
'rows' => $items | |
]; | |
} | |
return $row; | |
}); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment