php curl 爬虫多线程,tp5使用curl特性进行定时多线程爬虫(或任务),使用redis队列

利用php(以及开源工具)实现爬虫

流程说明

从数据库或者循环构建爬虫的url(包括分页参数)**

分段取出使用多线程保存数据到redis**

启用队列把数据保存到数据库**

开始

使用tp5.0的框架,安装爬虫扩展 QueryList 4.0

composer require jaeger/querylist

GitHub地址

2. 安装多线程curl扩展CurlMulti 插件

composer require jaeger/querylist-curl-multi

GitHub地址

3. 如果需要运行js脚本,安装PhantomJS 插件

composer require jaeger/querylist-phantomjs

GitHub地址

4. 安装tp5的队列扩展

composer require topthink/think-queue

GitHub地址

5. 安装taskPHP扩展使用php的cli模式(不超时也可定时执行程序)

composer require taskphp/taskphp dev-master

配置使用

queue配置(/extra/queue.php)

return [

// 'connector' => 'Database', // 数据库驱动

// 'expire' => null, // 任务的过期时间,默认为60秒; 若要禁用,则设置为 null

// 'default' => 'default', // 默认的队列名称

// 'table' => 'prefix_jobs', // 存储消息的表名,不带前缀

// 'dsn' => [],

// --------------------

'connector' => 'Redis', // Redis 驱动

'expire' => null, // 任务的过期时间,默认为60秒; 若要禁用,则设置为 null

'default' => 'default2', // 默认的队列名称

'host' => '127.0.0.1', // redis 主机ip

'port' => 6379, // redis 端口

'password' => '', // redis 密码

'select' => 0, // 使用哪一个 db,默认为 db0

'timeout' => 0, // redis连接的超时时间

'persistent' => false, // 是否是长连接s

];

taskphp配置

namespace app\index\controller;

use think\console\Command;

use think\console\Input;

use think\console\input\Argument;

use think\console\Output;

// 载入taskphp入口文件

require_once dirname(APP_PATH) . '/vendor/taskphp/taskphp/src/taskphp/base.php';

class Taskphp extends Command

{

protected function get_config()

{

return [

//任务列表

'task_list' => [

//key为任务名,多任务下名称必须唯一

// 'all' => [

// 'callback' => ['app\\index\\controller\\Demo', 'run'], //任务调用:类名和方法

// //指定任务进程最大内存 系统默认为512M

// 'worker_memory' => '2048M',

// //开启任务进程的多线程模式

// 'worker_pthreads' => false,

// //任务的进程数 系统默认1

// 'worker_count' => 1,

// //crontad格式 :秒 分 时 天 月 年 周 // 大概是6分钟 执行一个周期

// 'crontab' => '1 * * * * * *',

// ],

// 'bufen' => [

// 'callback' => ['app\\index\\controller\\Demo', 'run2'], //任务调用:类名和方法

// //指定任务进程最大内存 系统默认为512M

// 'worker_memory' => '1024M',

// //开启任务进程的多线程模式

// 'worker_pthreads' => false,

// //任务的进程数 系统默认1

// 'worker_count' => 1,

// //crontad格式 :秒 分 时 天 月 年 周 // 大概是6分钟 执行一个周期

// 'crontab' => '1 * * * * * *',

// ],

// 'bufenRedis' => [

// 'callback' => ['app\\index\\controller\\Demo', 'run3'], //任务调用:类名和方法

// //指定任务进程最大内存 系统默认为512M

// 'worker_memory' => '1024M',

// //开启任务进程的多线程模式

// 'worker_pthreads' => false,

// //任务的进程数 系统默认1

// 'worker_count' => 1,

// //crontad格式 :秒 分 时 天 月 年 周 // 大概是6分钟 执行一个周期

// 'crontab' => '1 * * * * * *',

// ],

],

];

}

protected function configure()

{

$this->addArgument('param', Argument::OPTIONAL);

// 设置命令名称

$this->setName($_SERVER['argv'][1])->setDescription('this is a taskphp!');

}

protected function execute(Input $input, Output $output)

{

//系统配置

$config = $this->get_config();

//加载配置信息

\taskphp\Config::load($config);

//定义启动文件入口标记

define("START_PATH", dirname(APP_PATH));

//运行框架

\taskphp\App::run();

}

}

主逻辑

namespace app\index\controller;

use QL\Ext\CurlMulti;

use QL\Ext\PhantomJs;

use QL\QueryList;

use think\Db;

use think\Queue;

class Test

{

# 逻辑

# 使用定时任务执行所有的 make_url

# 段查数据形成uri段 make_url

# 把段查数据加入到多线程爬虫里面 start

# 得到的所有的数据加入到Redis队列 push

# 最后加入数据库 [多线程使用startnojs,js可执行文件文件会遇到进程阻塞]

// php think queue:listen

// php think queue:work --daemon(不加--daemon为执行单个任务)

// php think queue:work --queue PaChongShuJu --daemon

/**

* 段查门店id

* @return [type] [description]

*/

public function make_url()

{

set_time_limit(0);

DB::table('aid')->chunk(200, function ($datas) {

$url = [];

foreach ($datas as $data) {

$url[] = 'http://i.meituan.com/poi/' . $data['aid'];

}

$this->startnojs($url);

});

// 测试

// $url = [

// 'http://i.meituan.com/poi/71225712',

// 'http://i.meituan.com/poi/116558576',

// ];

// $data['aid'] = 1;

// $this->start($url, $data['aid']);

}

public function startnojs($url = [])

{

$ql = QueryList::getInstance();

$ql->use(CurlMulti::class);

$ql->rules(['html' => ['html', 'html', '']])

->curlMulti($url)

->success(function (QueryList $ql, CurlMulti $curl, $r) {

$p = $r['info']['url'];

$pid = substr($p, 25);

$ret2 = $ql->getHtml();

preg_match("/这家店不错哦,一起去吧!(.*?)。\"/", $ret2, $m);

if (!empty($m)) {

if (!empty($m[1])) {

$pieces = explode(",", $m[1]);

$data = [

'name' => $pieces[0],

'address' => $pieces[1],

'mobile' => $pieces[2],

'p' => $pid,

];

$count = Db::table('info')->where('address', $pieces[1])->count();

if ($count > 0) {

} else {

$this->push($data);

}

}

}

$ql->destruct();

})->start([

'maxThread' => 100,

'maxTry' => 3,

]);

}

/**

* 多线程+cookie爬虫

* @return [type] [description]

*/

public function start($url = [])

{

$ql = QueryList::getInstance();

$ql->use(CurlMulti::class);

$ql->use(PhantomJs::class, 'D:/phantomjs-2.1.1-windows/bin/phantomjs.exe');

$ql->rules(['html' => ['html', 'html', '']])

->curlMulti($url)

->success(function (QueryList $ql, CurlMulti $curl, $r) {

$p = $r['info']['url'];

$pid = substr($p, 25);

$ret = $ql->browser(function (\JonnyW\PhantomJs\Http\RequestInterface $r) use ($p, $pid) {

$r->setMethod('GET');

$r->addHeader('Accept', 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8');

// $r->addHeader('Referer', 'http://cq.meituan.com/s/%E5%90%83%E9%A5%AD/');

$r->addHeader('User-Agent', 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.181 YaBrowser/18.4.0.2080 Yowser/2.5 Safari/537.36');

$r->addHeader('Cookie', 'IKUT=9156; BAIDUID=AA818089000D26F1B318D034B442113F:FG=1; BIDUPSID=AA818089000D26F1B318D034B442113F; PSTM=1526021220; BDUSS=h5dVM2Zk56OTIydUk2TFNFZzExVDBHOFNZQXhMOH5yVHFyQTRaaWRycHdBQzViQVFBQUFBJCQAAAAAAAAAAAEAAADXQoYktKi452pjAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHBzBltwcwZbTk; Hm_lvt_16bc67e4f6394c05d03992ea0a0e9123=1526714879,1527237021,1527237078; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; Hm_lvt_6859ce5aaf00fb00387e6434e4fcc925=1527583339,1527645854,1527650790,1527651051; PSINO=3; locale=zh; H_PS_PSSID=1449_21111; Hm_lpvt_6859ce5aaf00fb00387e6434e4fcc925=1527652553');

$r->setUrl($p);

$r->setTimeout(10000); // 10 seconds

$r->setDelay(3); // 3 seconds

return $r;

});

$ret2 = $ret->getHtml();

preg_match("/这家店不错哦,一起去吧!(.*?)。\"/", $ret2, $m);

if (!empty($m)) {

if (!empty($m[1])) {

$pieces = explode(",", $m[1]);

$data = [

'name' => $pieces[0],

'address' => $pieces[1],

'mobile' => $pieces[2],

'p' => $pid,

];

$count = Db::table('info')->where('address', $pieces[1])->count();

if ($count > 0) {

} else {

$this->push($data);

}

}

}

$ql->destruct();

})->start([

'maxThread' => 20,

'maxTry' => 3,

]);

}

/**

* 推送列队

* @param array $data [description]

* @return [type] [description]

*/

public function push($data = [])

{

$jobData = json_encode($data);

$jobHandlerClassName = 'app\index\controller\Job';

$jobQueueName = "PaChongShuJu";

$isPushed = Queue::push($jobHandlerClassName, $jobData, $jobQueueName);

// if ($isPushed) {

// echo "ok";

// }else{

// var_dump($isPushed);

// }

}

}

job文件

namespace app\index\controller;

use think\Db;

use think\queue\Job as QueueJob;

class Job

{

public function fire(QueueJob $job, $data)

{

$pieces = json_encode($data);

$this->add_db($pieces);

if ($job->attempts() > 3) {

//通过这个方法可以检查这个任务已经重试了几次了

$job->delete();

}

//如果任务执行成功后 记得删除任务,不然这个任务会重复执行,直到达到最大重试次数后失败后,执行failed方法

$job->delete();

// 也可以重新发布这个任务

// $job->release($delay); //$delay为延迟时间

}

public function failed($data)

{

// ...任务达到最大重试次数后,失败了

}

public function add_db($data = [])

{

$data = (array) json_decode(json_decode($data));

$count = Db::table('info')->where('address', $data['address'])->count();

if ($count == 0) {

Db::table('info')->insert($data);

}

}

}

taskPHP任务入口程序

namespace app\index\controller;

use taskphp\Utils;

use think\Db;

use QL\Ext\CurlMulti;

use QL\Ext\PhantomJs;

use QL\QueryList;

/**

* 测试任务

*/

class Demo

{

/**

* demo任务入口

*/

public static function run()

{

$papachong = new \app\index\controller\Chong();

$papachong->once();

}

public static function run2()

{

$papachong = new \app\index\controller\Chong();

$papachong->once2();

}

public static function run3()

{

$papachong = new \app\index\controller\Test();

$papachong->make_url();

}

}

tp5命令行配置文件(application/command.php)

return [

'app\index\controller\Taskphp',

'think\queue\command\Listen',

'think\queue\command\Restart',

'think\queue\command\Subscribe',

'think\queue\command\Work',

];

执行开始

开启redis服务器

运行监听队列

php think queue:work --queue PaChongShuJu

运行taskPHP任务(win直接运行目录下面的bat文件)开始爬虫

php think start

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值