Skocz do zawartości
  • 0

Skrypt który znajdzie miejsce na liście globalnych bestsellerów steama


Dziki__Wonsz
 Udostępnij

Pytanie

Witam, czy znacie jakiś sposób usprawnienia tego co w tytule. Aktualnie mój skrypt przeszukuje pierwszych 25 stron globalnych bestsellerów, pobiera wszystko, sprawdza wszystko po kolei i gdy znajdzie odpowiedni tytuł, zapisuje jego miejsce oraz stronę w tabeli, po czym wysyła to wszystko do bazy danych.
Jeżeli skrypt spisuje wszystkie tytuły z 25 stron zajmuje to ~30sek, jeśli natomiast wyszukuje np. 4 tytuły zajmuje to ~6s.
Zastanawiam się czy jest możliwość usprawienia tego precederu.


 

<?php
error_reporting(E_ALL);
include_once('Strona/libs/simple_html_dom.php');
$servername = "localhost";
$login = "root";
$pass = "";
$db = "steamadv";
$conn = new mysqli ($servername, $login, $pass, $db);  // Połączenie z bazą danych
$conn->query("SET CHARSET utf8");  // Ustawienie polskiego kodowania
$nazwa_tabeli = "SteamGry1";  // Przypisanie nazwy tabeli do zmiennej
$time = date("H:i:s");  // Zapisanie czasu do zmiennej
$appid = 'data-ds-appid';           //  /
$bundleid = 'data-ds-bundleid';     //  |    Przypisanie zmiennych do pobrania ID Aplikacji
$packageid = 'data-ds-packageid';   //  \
$y = 1;
for ($x = 1; $x <= 25; $x++) {
$i = 0;
$o = 0;
$p = 0;
$g = 0;
$html = file_get_html("https://store.steampowered.com/search/results?filter=globaltopsellers&snr=1_7_7_globaltopsellers_7&page=$x");
foreach($html->find('span.title') as $title) {
  $tytul = substr($title,20,-7);
  $tytul2 = str_replace("'", "''", "$tytul");   // Pobranie tytułu i zapisanie go do tablicy
  $tytulz[$i] = $tytul2;
  $i++;
}
foreach($html->find('a') as $link) {
  $link2 = $link->href;
  $linkz[$g] = $link2;    //Pobranie linku do gry i zapisanie go do tablicy
  $g++;
}

foreach ($html->find('a') as $id) {
      if ($id->$packageid > 0){       //
      $idp = $id->$packageid;         //
      $idr[$o] = $idp;                //
      $o++;                           //
    } elseif ($id->$appid != "") {    //
      $idp = $id->$appid;             //   Pobranie id gry i zapisanie go do tablicy
      $idr[$o] = $idp;                //
      $o++;                           //
    } else {                          //
      $idp = $id->$bundleid;          //
      $idr[$o] = $idp;                //
      $o++;
    }
}
foreach ($html->find('div.search_price') as $cena) {
  $cena2 = substr($cena,-23,-22);
if ($cena2 != '1' && $cena2 != '2' && $cena2 != '3' && $cena2 != '4' && $cena2 != '5' && $cena2 != '6' && $cena2 != '7' && $cena2 != '8' && $cena2 != '9' && $cena2 != '0') {     //
  $cena3 = substr($cena,-22,-21);                                                                                                                                                 //
if ($cena3 != '1' && $cena3 != '2' && $cena3 != '3' && $cena3 != '4' && $cena3 != '5' && $cena3 != '6' && $cena3 != '7' && $cena3 != '8' && $cena3 != '9' && $cena3 != '0') {     // Sprawdzenie kosztu gry
  $cena4 = substr($cena,-21,-20);                                                                                                                                                 //
if ($cena4 != '1' && $cena4 != '2' && $cena4 != '3' && $cena4 != '4' && $cena4 != '5' && $cena4 != '6' && $cena4 != '7' && $cena4 != '8' && $cena4 != '9' && $cena4 != '0') {     //
      $cena5 = substr($cena,-20,-13);
      $cenaz[$p] = $cena5;                //
      $p++;                               //
  } else {                                //
    $cena5 = substr($cena,-21,-13);       //
    $cenaz[$p] = $cena5;                  //
    $p++;                                 //  Przycięcie string'a z ceną,
  }                                       //  a następnie zapisanie go
} else {                                  //  do tablicy
  $cena5 = substr($cena,-22,-13);         //
  $cenaz[$p] = $cena5;                    //
  $p++;                                   //
}                                         //
} else {                                  //
  $cena5 = substr($cena,-23,-13);         //
  $cenaz[$p] = $cena5;                    //
  $p++;
}
}
for ($r = 0; $r <= 24; $r++) {                                                                                                                                      //
$sql = "INSERT INTO $nazwa_tabeli (Strona, Tytul, AppId, Cena, Link, Czas_Odczytu) VALUES ('$x', '$tytulz[$r]', '$idr[$r]', '$cenaz[$r]', '$linkz[$r]', '$time')";  // Pętla wysyłająca zapisane dane do tablicy
$result = $conn->query($sql);                                                                                                                                       //
}
}

  ?>

 

Edytowane przez Dziki__Wonsz

K4QaiyA.gif

Odnośnik do komentarza
Udostępnij na innych stronach

9 odpowiedzi na to pytanie

Rekomendowane odpowiedzi

  • 0

Dlaczego zrobiłeś crawler skoro mogłeś użyć oficjalnego API?

https://steamcommunity.com/dev

Request będzie szybszy, a do tego odejdzie Ci mnóstwo operacji związanych z wyciąganiem danych z HTMLa.

Połączenie do bazy otwieraj bezpośrednio przed wykonaniem zapytania, a nie na samym początku pliku (Bo po co? Zapobiegawczo? Gdzie ta baza Ci ucieknie?).

Edytowane przez orkin
Odnośnik do komentarza
Udostępnij na innych stronach

  • 0

@orkin

Miałem mu to proponować, ale nie znalazłem żadnego endpoint'u dla listy bestsellerów. Gdzie otworzy połączenie nie ma znaczenia, jakby wyrzucił to do osobnego pliku i go dołączył i tak by się to wcześniej wywołało. Główne zastrzeżenia jakie można mieć do tego kodu to ten fragment:

for ($r = 0; $r <= 24; $r++) {                                                                                                                                      //
$sql = "INSERT INTO $nazwa_tabeli (Strona, Tytul, AppId, Cena, Link, Czas_Odczytu) VALUES ('$x', '$tytulz[$r]', '$idr[$r]', '$cenaz[$r]', '$linkz[$r]', '$time')";  // Pętla wysyłająca zapisane dane do tablicy
$result = $conn->query($sql);                                                                                                                                       //
}

Wywoływanie 24 zapytań to głupota. Lepiej to zrobić używając transakcji. Wtedy przed pętlą otwierasz transakcje, w pętli robisz query, a poza pętlą commit. Tutaj jest opcja zaoszczędzić na czasie.

foreach($html->find('a') as $link) {
  $link2 = $link->href;
  $linkz[$g] = $link2;    //Pobranie linku do gry i zapisanie go do tablicy
  $g++;
}

foreach ($html->find('a') as $id) {
      if ($id->$packageid > 0){       //
      $idp = $id->$packageid;         //
      $idr[$o] = $idp;                //
      $o++;                           //
    } elseif ($id->$appid != "") {    //
      $idp = $id->$appid;             //   Pobranie id gry i zapisanie go do tablicy
      $idr[$o] = $idp;                //
      $o++;                           //
    } else {                          //
      $idp = $id->$bundleid;          //
      $idr[$o] = $idp;                //
      $o++;
    }
}

To niepotrzebnie jest rozbite na dwie pętle.

$conn->query("SET CHARSET utf8");  // Ustawienie polskiego kodowania

To można ustawić w bazie, ale to będą jakieś totalne ms.

Na pierwszy rzut oka nic poważniejszego tu nie widzę co dałoby wyraźny boost do czasu. Dodatkowo zmień lepiej styl komentowania kodu, bo to wprowadza niepotrzebny bajzel. Jedna zmiana w linijce i spędzisz czas na równaniu tej niepotrzebnej linii z komentarzy. Czemu nie możesz zamiast tego wyżej zrobić po prostu

//Pobranie id gry i zapisanie go do tablicy

//lub

/*
 * Pobranie id gry i zapisanie go do tablicy
 */
foreach ($html->find('a') as $id) {
      if ($id->$packageid > 0){
      $idp = $id->$packageid;
      $idr[$o] = $idp;
      $o++;
    } elseif ($id->$appid != "") {
      $idp = $id->$appid;
      $idr[$o] = $idp;
      $o++;
    } else {
      $idp = $id->$bundleid;
      $idr[$o] = $idp;
      $o++;
    }
}

Pomijając fakt mieszania w zmiennych polskiego z angielskim.

Odnośnik do komentarza
Udostępnij na innych stronach

  • 0
3 godziny temu, Wolen napisał:

@orkin

Miałem mu to proponować, ale nie znalazłem żadnego endpoint'u dla listy bestsellerów. Gdzie otworzy połączenie nie ma znaczenia, jakby wyrzucił to do osobnego pliku i go dołączył i tak by się to wcześniej wywołało. Główne zastrzeżenia jakie można mieć do tego kodu to ten fragment:

for ($r = 0; $r <= 24; $r++) {                                                                                                                                      //
$sql = "INSERT INTO $nazwa_tabeli (Strona, Tytul, AppId, Cena, Link, Czas_Odczytu) VALUES ('$x', '$tytulz[$r]', '$idr[$r]', '$cenaz[$r]', '$linkz[$r]', '$time')";  // Pętla wysyłająca zapisane dane do tablicy
$result = $conn->query($sql);                                                                                                                                       //
}

Wywoływanie 24 zapytań to głupota. Lepiej to zrobić używając transakcji. Wtedy przed pętlą otwierasz transakcje, w pętli robisz query, a poza pętlą commit. Tutaj jest opcja zaoszczędzić na czasie.

foreach($html->find('a') as $link) {
  $link2 = $link->href;
  $linkz[$g] = $link2;    //Pobranie linku do gry i zapisanie go do tablicy
  $g++;
}

foreach ($html->find('a') as $id) {
      if ($id->$packageid > 0){       //
      $idp = $id->$packageid;         //
      $idr[$o] = $idp;                //
      $o++;                           //
    } elseif ($id->$appid != "") {    //
      $idp = $id->$appid;             //   Pobranie id gry i zapisanie go do tablicy
      $idr[$o] = $idp;                //
      $o++;                           //
    } else {                          //
      $idp = $id->$bundleid;          //
      $idr[$o] = $idp;                //
      $o++;
    }
}

To niepotrzebnie jest rozbite na dwie pętle.

$conn->query("SET CHARSET utf8");  // Ustawienie polskiego kodowania

To można ustawić w bazie, ale to będą jakieś totalne ms.

Na pierwszy rzut oka nic poważniejszego tu nie widzę co dałoby wyraźny boost do czasu. Dodatkowo zmień lepiej styl komentowania kodu, bo to wprowadza niepotrzebny bajzel. Jedna zmiana w linijce i spędzisz czas na równaniu tej niepotrzebnej linii z komentarzy. Czemu nie możesz zamiast tego wyżej zrobić po prostu

//Pobranie id gry i zapisanie go do tablicy

//lub

/*
 * Pobranie id gry i zapisanie go do tablicy
 */
foreach ($html->find('a') as $id) {
      if ($id->$packageid > 0){
      $idp = $id->$packageid;
      $idr[$o] = $idp;
      $o++;
    } elseif ($id->$appid != "") {
      $idp = $id->$appid;
      $idr[$o] = $idp;
      $o++;
    } else {
      $idp = $id->$bundleid;
      $idr[$o] = $idp;
      $o++;
    }
}

Pomijając fakt mieszania w zmiennych polskiego z angielskim.

Kodowanie ustawiłem, bo tylko dzięki temu, w bazie danych posiadałem wszystkie polskie znaki. Przy ustawianiu ręcznym nie potrafiło się to przestawić. (Możliwe że wina xampp'a).
W sumie transakcja ma większy sens, ogarnę kod i dam znać.

K4QaiyA.gif

Odnośnik do komentarza
Udostępnij na innych stronach

  • 0
13 godzin temu, Wolen napisał:

@orkin

Miałem mu to proponować, ale nie znalazłem żadnego endpoint'u dla listy bestsellerów. Gdzie otworzy połączenie nie ma znaczenia, jakby wyrzucił to do osobnego pliku i go dołączył i tak by się to wcześniej wywołało. Główne zastrzeżenia jakie można mieć do tego kodu to ten fragment:

for ($r = 0; $r <= 24; $r++) {                                                                                                                                      //
$sql = "INSERT INTO $nazwa_tabeli (Strona, Tytul, AppId, Cena, Link, Czas_Odczytu) VALUES ('$x', '$tytulz[$r]', '$idr[$r]', '$cenaz[$r]', '$linkz[$r]', '$time')";  // Pętla wysyłająca zapisane dane do tablicy
$result = $conn->query($sql);                                                                                                                                       //
}

Wywoływanie 24 zapytań to głupota. Lepiej to zrobić używając transakcji. Wtedy przed pętlą otwierasz transakcje, w pętli robisz query, a poza pętlą commit. Tutaj jest opcja zaoszczędzić na czasie.

Ma znaczenie, bo jak sam powiedział, jego skrypt wykonuje się około 30 sekund. Więc skoro otwiera połączenie na samym początku skryptu, to blokuje zasób (w tym przypadku jedno z ograniczonej ilości połączeń) na cały ten czas. To są złe praktyki i nie powinno się tak robić.

 

Albo może po prostu w VALUES dać kolejne rekordy po przecinku. Pełna dowolność.

Odnośnik do komentarza
Udostępnij na innych stronach

  • 0

W sumie. Tak po przemyśleniu Doctrine łączy się dopiero przy flushu. Frameworki rozleniwiają :v.

Można dodać values po przecinku, ale transakcje jak dla mnie są "ładniejsze" i przy np. dużej ilości danych jednak powinno się ich używać, przynajmniej nie spotkałem się żeby ktoś robił to inaczej.

A będąc jeszcze w temacie, jak 30 sekund to za wolno zawsze zostaje napisanie mikroserwisu w innym języku.

Odnośnik do komentarza
Udostępnij na innych stronach

Jeśli chcesz dodać odpowiedź, zaloguj się lub zarejestruj nowe konto

Jedynie zarejestrowani użytkownicy mogą komentować zawartość tej strony.

Zarejestruj nowe konto

Załóż nowe konto. To bardzo proste!

Zarejestruj się

Zaloguj się

Zaloguj się poniżej.

Zaloguj się
 Udostępnij

  • Ostatnio przeglądający forum Skrypt który znajdzie miejsce na liście globalnych bestsellerów steama   0 użytkowników
    • Brak zarejestrowanych użytkowników przeglądających tę stronę.
×
×
  • Dodaj nową pozycję...