PHP에서도 동적 사이트를 스크래핑하고 싶은 밤

15519 단어 PHP스크래핑

시작하기



이것은 지즈 아카데미 Advent Calendar 2020 기사입니다!

서장 - 난 스크래핑 할거야, PHP에서. -



대체로 스크래핑이라고 하면, 시세는 python 라고 정해져 있습니다.
하지만 평소 PHP를 만지고 있는 나는 PHP로 스크래핑하고 싶습니다.

그래서 PHP로 스크래핑이라고 하면 대체로 phpQuery 라는 것이 언급되기 쉽습니다.
확실히, jQuery처럼 조작할 수 있으므로 간단합니다.
하지만, 이것 동적 사이트에는 잘 이용할 수 없네요.

그래서 다른 방법이 필요합니다.

이번 대상.



모 해외 쇼핑 사이트 (일단 이름은 덮을 수 있습니다.)
다음과 같이
1. 검색
2. 일람표시(일부만)
3. 아래로 스크롤하면 스크롤한 만큼 정보를 취득한다
라는 움직임입니다.


첫째, 모든 정보가 검색되어 나열되면 phpQuery에서도 사용할 수 있습니다.
이것이라면 할 수 없습니다.

해결 방법



다음 도구를 사용하여 이동합니다.
  • selenium-server-standalone
  • selenium은의 웹 브라우저의 조작을 자동화해 주는 녀석.

  • Selenium Google 크롬 드라이버
  • selenium에서 Chrome을 움직일 수있는 사람.

  • facebook-webdriver
  • facebook-webdriver에서 위의 자동화를 PHP를 사용하여 수행 할 수 있습니다.


  • 라는 느낌입니다.

    그래서 이번 일의 이미지는
    1. selenium 브라우저에서 스크래핑하려는 사이트에 액세스합니다.
    2. 정보를 취득하고 싶은 페이지로 가서, 일단 맨 아래로 스크롤시킨다(스크롤하면, 전부의 정보가 표시되고 있다)
    3. 맨 아래로 스크롤했다 = 스크래핑하고 싶은 정보가 모두 표시되어 있기 때문에 그것을 스크래핑! ! ! !

    무슨 해킹!

    도구 준비



    이번 작업 디렉토리로 이동


    $ mkdir selenium
    $ cd selenium
    

    selenium-server-standalone 설치.


    homebrew 를 이용.
    brew install selenium-server-standalone
    

    Selenium Google 크롬 드라이버 다운로드



    링크
    어쩌면 여기 있을지도 ↓

    다운로드가 끝나면 selenium 디렉토리에 묻는다.

    facebook-webdriver 다운로드


    $ php composer.phar require facebook/webdriver
    

    만약, Could not open input file: composer.phar 라든지의 경우는, 이하의 참고가 될지도.
  • htps //w w. 면도 s mp. 코m/엔트리/2019/07/13/003852

  • 서버 시작


    $ selenium-server -port 4444 &
    $ selenium-server -port 4444 &
    [1] 33415
    C02SY1XFGTFJ:selenium username$ 18:04:14.512 INFO [GridLauncherV3.launch] - Selenium build info: version: '3.11.0', revision: 'e59cfb3'
    18:04:14.513 INFO [GridLauncherV3$1.launch] - Launching a standalone Selenium Server on port 4444
    2018-05-24 18:04:14.624:INFO::main: Logging initialized @441ms to org.seleniumhq.jetty9.util.log.StdErrLog
    18:04:14.882 INFO [SeleniumServer.boot] - Welcome to Selenium for Workgroups....
    18:04:14.882 INFO [SeleniumServer.boot] - Selenium Server is up and running on port 4444
    

    그래서, 아래와 같이되면
    $ jobs
    [1]+  Running                 selenium-server -port 4444 &
    

    PHP 파일 준비



    시험에, test.php 를 준비.
    <?php
    require './vendor/autoload.php';
    
    use Facebook\WebDriver\Chrome\ChromeOptions;
    use Facebook\WebDriver\Remote\DesiredCapabilities;
    use Facebook\WebDriver\Remote\RemoteWebDriver;
    use Facebook\WebDriver\WebDriverBy;
    use Facebook\WebDriver\WebDriverExpectedCondition;
    
    // 今回の買い物サイト用に準備する変数。
    // 検索したいワードを$wordに入れる。この例だとamazonと検索した場合
    $word = 'amazon';
    $title = " ********** "; // ここはhtmlのtitleに表示される文言を記述。そのサイトによって異なるので、一旦ブラウザでアクセスして確認してください。
    
    // chrome利用用意
    $options = new ChromeOptions();
    // headlessモードで対応
    $options->addArguments(['--headless']);
    // ブラウザのサイズを指定
    $options->addArguments(["window-size=1024,2048"]);
    
    $host = 'http://localhost:4444/wd/hub';
    $capabilities = Facebook\WebDriver\Remote\DesiredCapabilities::chrome();
    $capabilities->setCapability(ChromeOptions::CAPABILITY, $options);
    $driver = Facebook\WebDriver\Remote\RemoteWebDriver::create($host, $capabilities);
    //スクレイピングしたいアドレスを入力
    $driver->get('https://www.******/');
    $browserLogs = $driver->manage()->getLog('browser');
    // 検索したい語をsendKeys()に入れて、submitする。ここの'q'はサイトによって異なる。
    $element = $driver->findElement(WebDriverBy::name('q'));
    $element->sendKeys($word);
    $element->submit();
    
    // このサイトでは、商品画像を全部表示するため、画面を少し右に移動。場合によっては不要。Y軸を動かしたい場合は、第2引数の数字を変える。
    $driver->executeScript("window.scrollTo(300, 0);");
    $driver->wait(15)->until(
        WebDriverExpectedCondition::titleIs($title)
    );
    
    // もし、$title(htmlの<title>が想定どおりじゃない)がなければ、なにかした失敗していると判断
    if ($driver->getTitle() !== "$title") {
        throw new Exception('fail');
    }
    
    // 以下取得したい要素を指定してあげる。
    // 今回は、検索結果のURL、写真、名前を取得したいので以下の用になっている。
    // cssSelectorはサイトに寄って異なる。cssSelectorの中身を変えてね。
    $itemUrls = $driver->findElements(WebDriverBy::cssSelector('div.c2iYAv > div.cRjKsc > a'));
    $photos = $driver->findElements(WebDriverBy::cssSelector('.c5TXIP .c2iYAv .cRjKsc .c1ZEkM'));
    $productNames = $driver->findElements(WebDriverBy::cssSelector('.c5TXIP .c3KeDq .c16H9d'));
    
    $items = [];
    // 商品あるかチェック
    if (count($photos) < 0) {
        throw new Exception('no item.');
    }
    
    //。今回は上から10件だけ取得して、情報を$item配列に格納する。
    foreach ($itemUrls as $k => $v) {
        if ($k === 10) {
            break;
        }
        $items[$k]['$itemUrl'] = $v->getAttribute('href');
    }
    foreach ($photos as $k => $v) {
        if ($k === 10) {
            break;
        }
        $items[$k]['photoUrl'] = $v->getAttribute('src');
    }
    foreach ($productNames as $k => $v) {
        if ($k === 10) {
            break;
        }
        $items[$k]['titleName'] = $v->getText();
    }
    
    print_r($items);
    echo "\n";
    
    // ↓コメントアウト外せば、どこをスクレイピングしているかとスクリーンショットで確認できる↓
    // $file = "sumple_chrome.png";
    // $driver->takeScreenshot($file);
    $driver->close();
    

    ※selenium-webdriver의 사용법은 이쪽.
    링크

    걸면,$ php test.php에서 실행.

    좋은 느낌이 들었습니다.



    끝나면 kill한다.


    $ jobs
    [1]+  Running                 selenium-server -port 4444 &  (wd: ~/selenium)
    $ kill %1
    $ jobs
    [1]+  Exit 143                selenium-server -port 4444  (wd: ~/selenium)
    

    요약



    PHP에서도 동적 사이트를 스크래핑 할 수 있어요!

    좋은 웹페이지 즐겨찾기