文章851
标签121
分类10

PHP 爬虫踩坑实践

诶 最近总是踩坑实践 ... 然后未完待续 .

今天接到需求 需要抓 https://coinmarketcap.com 下各交易平台数据.

爬虫选型当然是python, but 身为phper 不用 php 写一下我怎么会死心呢!!!

前两天找 swoole 客户端的轮子 Saber 很人性化, 官方推荐的果然不错.

人性化使用风格, ajax.js/axios.js/requests.py用户福音, 同时支持PSR风格操作

好吧 我就用它了 !

部分代码展示:


$url = 'https://coinmarketcap.com/zh/exchanges/binance/';

go(function () use ($url) {
            [$repsonse] = SaberGM::list(['uri' => $url, 'proxy' => ['http://127.0.0.1:1234']]);

            $repsonse->getParsedDomObject()->
            getElementById('exchange-markets')->
            getElementsByTagName('tbody')->
            item(0)->
            getElementsByTagName('tr')->
            textContent;
  });

代码语法风格 是不是很熟悉 .

先说踩得第一个坑

PHP Fatal error: Class 'DOMDocument' not found

写的很明白 我没有 dome 类 百度一下 yum install php-xml, 试了下 当然不好使了 , 因为我的开发环境是 php7.2

yum search xml
yum install -y php72-php-xml.x86_64 

好了 这个坑就填完了

未完待续/...

PHP 大整数 / 科学计数法 转 字符串

json 数据格式 中 大整数解开 会被转换为科学计数法 使用 JSON_BIGINT_AS_STRING

json_decode 官方文档

json_decode($var, true, '512', JSON_BIGINT_AS_STRING)

PHP 科学计数法转字符串

<?PHP
 function ScToNum($num) {
    $numer = strtoupper($num);
    $parts = explode('E', $numer);
    list($int, $ex_str) = $parts;

    $exp = $ex_str[0];
    $var = substr($ex_str, 1);

    if ($exp == '+') {
        return bcmul($int, bcpow(10, $var));
    }

    return bcdiv($int, bcpow(10, $var));
}

[踩坑] Swoole 4.2 协程

首先注意

 'enable_coroutine' => false,     // 是否自动开启协程 默认 true

我当然false 手动 go 调用协程 先踩小坑

 go(): Using Xdebug in coroutines is extremely dangerous, please notice that it may lead to coredump! i

写了个接口测试下 就抛错了 , xdebug 不让用 说危险...

今天填下坑 2019/01/09 韩大大来做分享, 顿时觉得协程好牛逼!! 因为协程可以无限起.

Demo 示例:

 public function coTest()
 {
     go(function () {
         $time = time();
         $chan = new Coroutine\Channel();
         go(function () use ($chan) {
             co::sleep(1);

             $chan->push(1);
         });

         go(function () use ($chan) {
             co::sleep(1);
             $chan->push(2);
         });

         for ($i = 0; $i < 2; $i++) {
             echo $chan->pop(), PHP_EOL;
             echo 'pop :', time() - $time, PHP_EOL;
         }
     });
 }
$ php cli.php Tests coTest
$ game over
1
pop :1
2
pop :1

屌屌的 同一秒结束任务, 厉害了. 试想下以后写爬虫, 大流量访问worker 数不足等场景 都可以解决了, 只要内存足够, 协程就可以无限生成.

Swoole 4.2.3 以后 还有 使用 Swoole\Runtime::enableCoroutine() 方法 可以使原生方法:

可用列表

redis扩展
使用mysqlnd模式的pdo、mysqli扩展,如果未启用mysqlnd将不支持协程化

soap扩展
file_get_contents、fopen
stream_socket_client (predis)
stream_socket_server
fsockopen

其他方法只能等更新了 , swoole & php 以后会越来越好, 感谢热爱开源, 乐于分享的人.

2019/01/21 更新下新踩到的坑

我写了这样一个服务 里面接口有大量的代理请求中转接口 A 和 协程调用第三方接口 B.
在测试环境少量请求时效果不错, 使用协程大大的降低了 调用 B 接口的响应时间, 单在测试环境中全量测试, 大量的请求 A 接口,
因为并没有做worker 进程分配规则, 都是随机分配, 导致 协程调用 B 接口 特别慢, 经过测试找出原因应该就是 B 接口协程调用因为IO操作会让出worker进程给 A 接口请求.

参考地址: https://wiki.swoole.com/wiki/page/965.html

2019-09-04

协程服务注意事项 :
昨天测试服务修改 max_request = 1 导致大量协程请求失效, 该参数目的实现热更新不用重启swoole 服务即可更新代码 测试环境使用. 但使用协程服务时, worker 将任务丢入协程后 边重启..... 回包失败导致大量请求超时(进程死亡未主动挥手)...

">