php를 이용한 웹크롤링

의존성

composer.json

{
    "require": {
        "guzzlehttp/guzzle": "^7.0",
        "symfony/dom-crawler": "^5.3",
        "symfony/css-selector": "^5.3"
    }
}

요청과 응답페이지 요소탐색

use GuzzleHttp\Client;
use Symfony\Component\DomCrawler\Crawler;

$url = 'http://ujsstudio.com';
$client = new Client();
$res = $client->get($url);
$res = $res->getBody();
$html = (string)$res; // 문자열로 형변환
// dom 필터링
$crawler = new Crawler($html);
$nodeValues = $crawler->filter("#primary a")->each(function(Crawler $node, $i){
    return $node->attr('href');
});

페이지네이션 처리

use GuzzleHttp\Client;
use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Pool;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Psr7\Response;
use Symfony\Component\DomCrawler\Crawler;

$result = [];
$client = new Client();

// 페이지 조회 익명함수(제너레이터) 생성
$requests = function ($total) use ($client) {
    $uri = 'http://ujsstudio.com/page';
    for ($i = 0; $i < $total; $i++) {
        yield function() use ($client, $uri, &$i) {
            $uri = $uri.'/'.$i+1;
            return $client->getAsync($uri);
        };
    }
};

$pool = new Pool($client, $requests(10), [
        'concurrency' => 5,
        'fulfilled' => function (Response $response, $index) use (&$result) {
            $res = $response->getBody();
            $html = (string)$res;

            // 요소탐색
            $crawler = new Crawler($html);
            $nodeValues = $crawler->filter("#primary a")->each(function(Crawler $node, $i){
                return $node->attr('href');
            });

            $result[] = $nodeValues;
        },
        'rejected' => function (RequestException $reason, $index) {
            // this is delivered each failed request
        },
]);

$promise = $pool->promise();
$promise->wait();

[composer] autoload

composer를 사용해서 간단하게 autoload를 사용하는 방법

1. monolog 패키지 설치해보기

composer require monolog/monolog

2. 패키지 로드하기

index.php

<?php
include './vendor/autoload.php';

use Monolog\Logger;

$log = new Logger('name');

3. 내 클래스 로드해보기

컴포저 autoload는 psr-4 규칙을 따르고 있기 때문에 클래스 생성시 네임스페이스를 규칙에 맞게 정하고 composer.json 파일에 namespace prefix와 클래스를 정의한 디렉토리를 매핑해주는 설정을 추가한다.

composer.json

{
    "require": {
        "monolog/monolog": "^2.2"
    },
    "autoload": {
        "psr-4": { // Js 네임페이스 접두사를 lib에 매핑
            "Js\\" : "lib/" 
        }
    }
}
/lib/src/Foo.php

<?php
namespace Js\Src;

class Foo{
    public function say()
    {
        return 'hello';
    }
}
index.php

<?php
include './vendor/autoload.php';

use Monolog\Logger;
use Js\Src\Foo;

$log = new Logger('name');
$foo = new Foo();
echo $foo->say();
composer dump-autoload

Foo 클래스에서 사용한 Js 네임스페이스 접두사를 lib디렉토리에 매핑해 주었기 때문에 autoload가 실행 될때 자동으로 지정한 경로의 클래스를 로드할 수 있게 된다.

참조

  • composer.json schema
  • psr-4
  • http://blog.ujsstudio.com/2021/01/09/psr-4-%eb%84%a4%ec%9e%84%ec%8a%a4%ed%8e%98%ec%9d%b4%ec%8a%a4-%ea%b7%9c%ec%b9%99/

[composer] file could not be downloaded (http/1.1 404 not fund) 해결방법

라라벨 설치하는 과정에서 아래와 같은 에러 발생

 [Composer\Downloader\TransportException]
  The "https://packagist.org/p/provider-2020-01%24d05e2d9aae910523f4e326c5a73b6cc7b6d498492a6f115892377153193c21bd.js
  on" file could not be downloaded (HTTP/1.1 404 Not Found)

아래의 명령어를 순서대로 입력후 재설치

composer clear-cache
composer -vvv

참조:
https://github.com/composer/composer/issues/7021