HTTP客户端

HTTP客户端用于抓取网页HTML源码。


默认安装好QueryList之后就可以直接使用GuzzleHttp了:

  1. $client = new GuzzleHttp\Client();
  2. $res = $client->request('GET', 'https://www.baidu.com/s', [
  3. 'wd' => 'QueryList'
  4. ]);
  5. $html = (string)$res->getBody();
  6. $data = QueryList::html($html)->find('h3')->texts();

QueryList内置的HTTP客户端

为方便使用,QueryList基于GuzzleHttp封装了一些HTTP请求接口,并进行了简化,请求参数与GuzzleHttp一致,在请求参数上有什么不明白的地方可以直接查看GuzzleHttp文档。

目前封装的HTTP接口有:

  • get():GET 请求
  • post():POST请求
  • postJson():POST JSON请求
  • multiGet():并发GET请求
  • multiPost():并发POST请求


用法

get()方法和post()方法用法和参数完全一致,且共享cookie。

  1. $ql = QueryList::get('http://httpbin.org/get?param1=testvalue&params2=somevalue');
  2. // 等价于
  3. $ql->get('http://httpbin.org/get',[
  4. 'param1' => 'testvalue',
  5. 'params2' => 'somevalue'
  6. ]);
  7. // 发送post请求
  8. $ql = QueryList::post('http://httpbin.org/post',[
  9. 'param1' => 'testvalue',
  10. 'params2' => 'somevalue'
  11. ]);



自定义HTTP Header

  1. $ql = QueryList::get('http://httpbin.org/get',[
  2. 'param1' => 'testvalue',
  3. 'params2' => 'somevalue'
  4. ],[
  5. 'headers' => [
  6. 'Referer' => 'https://querylist.cc/',
  7. 'User-Agent' => 'testing/1.0',
  8. 'Accept' => 'application/json',
  9. 'X-Foo' => ['Bar', 'Baz'],
  10. // 携带cookie
  11. 'Cookie' => 'abc=111;xxx=222'
  12. ]
  13. ]);

更多高级参数

还可以携带更多高级参数,如:设置超时时间、设置代理等。

  1. $ql = QueryList::get('http://httpbin.org/get',[
  2. 'param1' => 'testvalue',
  3. 'params2' => 'somevalue'
  4. ],[
  5. // 设置代理
  6. 'proxy' => 'http://222.141.11.17:8118',
  7. //设置超时时间,单位:秒
  8. 'timeout' => 30,
  9. 'headers' => [
  10. 'Referer' => 'https://querylist.cc/',
  11. 'User-Agent' => 'testing/1.0',
  12. 'Accept' => 'application/json',
  13. 'X-Foo' => ['Bar', 'Baz'],
  14. 'Cookie' => 'abc=111;xxx=222'
  15. ]
  16. ]);
  17. $ql->post('http://httpbin.org/post',[
  18. 'param1' => 'testvalue',
  19. 'params2' => 'somevalue'
  20. ],[
  21. 'proxy' => 'http://222.141.11.17:8118',
  22. 'timeout' => 30,
  23. 'headers' => [
  24. 'Referer' => 'https://querylist.cc/',
  25. 'User-Agent' => 'testing/1.0',
  26. 'Accept' => 'application/json',
  27. 'X-Foo' => ['Bar', 'Baz'],
  28. 'Cookie' => 'abc=111;xxx=222'
  29. ]
  30. ]);

使用 HTTP Cache


HTTP缓存功能基于PHP-Cache包,它支持多种缓存驱动,如:文件缓存、Redis缓存,MySQL缓存等,PHP-Cache文档:http://www.php-cache.com/en/latest/

合理的使用HTTP缓存功能可以避免频繁的去抓取内容未改变的页面,提高采集效率,它会在第一次抓取页面HTML后,将页面HTML缓存下来,下一次再次抓取时直接从缓存中读取HTML内容。

使用文件缓存驱动
  1. // 缓存文件夹路径
  2. $cache_path = __DIR__.'/temp/';
  3. $ql = = QueryList::get($url,null,[
  4. 'cache' => $cache_path,
  5. 'cache_ttl' => 600 // 缓存有效时间,单位:秒,可以不设置缓存有效时间
  6. ]);
使用其它缓存驱动

以使用Predis缓存驱动为例,首先安装Predis缓存适配器

  1. composer require cache/predis-adapter

使用Predis缓存驱动:

  1. use Cache\Adapter\Predis\PredisCachePool;
  2. $client = new \Predis\Client('tcp:/127.0.0.1:6379');
  3. $pool = new PredisCachePool($client);
  4. $ql = = QueryList::get($url,null,[
  5. 'cache' => $pool,
  6. 'cache_ttl' => 600 // 缓存有效时间,单位:秒,可以不设置缓存有效时间
  7. ]);

并发请求(多线程请求)

简单用法,默认并发数为5

  1. use GuzzleHttp\Psr7\Response;
  2. use QL\QueryList;
  3. $urls = [
  4. 'https://github.com/trending/go?since=daily',
  5. 'https://github.com/trending/html?since=daily',
  6. 'https://github.com/trending/java?since=daily'
  7. ];
  8. QueryList::multiGet($urls)
  9. ->success(function(QueryList $ql,Response $response, $index) use($urls){
  10. echo 'Current url: '.$urls[$index]."\r\n";
  11. $data = $ql->find('h3>a')->texts();
  12. print_r($data->all());
  13. })->send();

更高级的用法

  1. use GuzzleHttp\Psr7\Response;
  2. use QL\QueryList;
  3. $urls = [
  4. 'https://github.com/trending/go?since=daily',
  5. 'https://github.com/trending/html?since=daily',
  6. 'https://github.com/trending/java?since=daily'
  7. ];
  8. $rules = [
  9. 'name' => ['h3>a','text'],
  10. 'desc' => ['.py-1','text']
  11. ];
  12. $range = '.repo-list>li';
  13. QueryList::rules($rules)
  14. ->range($range)
  15. ->multiGet($urls)
  16. // 设置并发数为2
  17. ->concurrency(2)
  18. // 设置GuzzleHttp的一些其他选项
  19. ->withOptions([
  20. 'timeout' => 60
  21. ])
  22. // 设置HTTP Header
  23. ->withHeaders([
  24. 'User-Agent' => 'QueryList'
  25. ])
  26. // HTTP success回调函数
  27. ->success(function (QueryList $ql, Response $response, $index){
  28. $data = $ql->queryData();
  29. print_r($data);
  30. })
  31. // HTTP error回调函数
  32. ->error(function (QueryList $ql, $reason, $index){
  33. // ...
  34. })
  35. ->send();

连贯操作

post操作和get操作是cookie共享的,意味着你可以先调用post()方法登录,然后get()方法就可以采集所有登录后的页面。

  1. $ql = QueryList::post('http://xxxx.com/login',[
  2. 'username' => 'admin',
  3. 'password' => '123456'
  4. ])->get('http://xxx.com/admin');
  5. $ql->get('http://xxx.com/admin/page');


获取抓取到的HTML

使用getHtml()方法可以获取到get()post()方法返回的HTML内容,通常用于调试打印验证抓取结果等场景。

  1. $ql = QueryList::get('http://httpbin.org/get?param1=testvalue');
  2. echo $ql->getHtml();



捕获HTTP异常


如果遇到HTTP错误,如:404,500等,QueryList就会抛出HTTP异常,并终止程序。如果你不想出现HTTP异常时程序终止,可以自己捕获异常并处理,更多关于HTTP异常的细节:http://guzzle-cn.readthedocs.io/zh_CN/latest/quickstart.html#id13

  1. use QL\QueryList;
  2. use GuzzleHttp\Exception\RequestException;
  3. try{
  4. $ql = QueryList::get('https://www.sfasd34234324.com');
  5. }catch(RequestException $e){
  6. //print_r($e->getRequest());
  7. echo 'Http Error';
  8. }
{primary} 相关专题:忽略HTTP异常


获取HTTP响应头等信息

如果你想获取HTTP响应头,如响应状态码,QueryList内置的HTTP客户端屏蔽了这部分功能,请直接使用GuzzleHttp来实现。

  1. use GuzzleHttp\Client;
  2. $client = new Client();
  3. $response = $client->get('http://httpbin.org/get');
  4. // 获取响应头部信息
  5. $headers = $response->getHeaders();
  6. print_r($headers);



自定义HTTP客户端

GuzzleHttp是一款功能非常强大的HTTP客户端,你想要的功能它几乎都有;但如果你还是想使用自己熟悉的HTTP客户端如:curl,那也是可以的:

  1. function getHtml($url)
  2. {
  3. $ch = curl_init();
  4. curl_setopt($ch, CURLOPT_URL, $url);
  5. curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
  6. curl_setopt($ch, CURLOPT_AUTOREFERER, true);
  7. curl_setopt($ch, CURLOPT_REFERER, $url);
  8. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  9. $result = curl_exec($ch);
  10. curl_close($ch);
  11. return $result;
  12. }
  13. $html = getHtml('http://httpbin.org/get?param1=testvalue');
  14. // 这种情况下允许你对HTML做一些额外的处理后,然后再把HTML传给QueryList对象
  15. $html = str_replace('xxx','yyy',$html);
  16. $ql = QueryList::html($html);
  17. echo $ql->getHtml();

通过其他HTTP客户端获取源码,然后使用html()方法来设置html,html()方法除了可以接收一个完整的HTML网页外,还支持接收HTML片段:

  1. $html = <<<STR
  2. <div id="one">
  3. <div class="two">
  4. <a href="http://querylist.cc">QueryList官网</a>
  5. <img src="http://querylist.com/1.jpg" alt="这是图片">
  6. <img src="http://querylist.com/2.jpg" alt="这是图片2">
  7. </div>
  8. <span>其它的<b>一些</b>文本</span>
  9. </div>
  10. STR;
  11. $ql = QueryList::html($html);
{warning} phpQuery有个bug,那就是当HTML中有它无法识别的特殊字符时,HTML就会被截断,导致最终的采集结果不正确,此时可以尝试使用正则或其它方式获取到要采集的内容的HTML片段,把这个HTML片段传给QueryList,从而可以解决这种场景下的问题。