# Beanbun
Beanbun 是用 PHP 编写的多进程网络爬虫框架,具有良好的开放性、高可扩展性。
## 简介
Beanbun 是一个简单可扩展的爬虫框架,支持守护进程模式与普通模式,守护进程模式基于 [Workerman](http://www.workerman.net),下载器基于 [Guzzle](http://guzzle.org)。
框架名称来自于作者家的猫,此猫名叫门丁,“门丁”是北方的一种面点。门丁 -> 豆包 -> bean bun
<img src="/images/mending.jpg" alt="label" width="300">
## 特点
- 支持守护进程与普通两种模式(守护进程模式只支持 Linux 服务器)
- 默认使用 Guzzle 进行爬取
- 支持分布式
- 支持内存、Redis 等多种队列方式
- 支持自定义URI过滤
- 支持广度优先和深度优先两种爬取方式
- 遵循 PSR-4 标准
- 爬取网页分为多步,每步均支持自定义动作(如添加代理、修改 user-agent 等)
- 灵活的扩展机制,可方便的为框架制作插件:自定义队列、自定义爬取方式...
## 安装
Beanbun 可以通过 composer 进行安装。
```
$ composer require kiddyu/beanbun
```
## 快速开始
创建一个文件 start.php,包含以下内容
``` php
<?php
require_once(__DIR__ . '/vendor/autoload.php');
use Beanbun\Beanbun;
$beanbun = new Beanbun;
$beanbun->seed = [
'http://www.950d.com/',
'http://www.950d.com/list-1.html',
'http://www.950d.com/list-2.html',
];
$beanbun->afterDownloadPage = function($beanbun) {
file_put_contents(__DIR__ . '/' . md5($beanbun->url), $beanbun->page);
};
$beanbun->start();
```
在命令行中执行
```
$ php start.php
```
接下来就可以看到抓取的日志了。
## 使用
### 启动与停止
上面的例子中,爬虫是以普通模式运行的,上面的代码放在网站项目中,也可以正常执行,如果我们想让爬虫一直执行,就需要使用守护进程模式。同样是上面的代码,我们只需要把执行的命令增加一个 start 参数,即会变成守护进程模式。
```
$ php start.php start
```
需要说明的是,普通模式下不依赖队列,爬虫只爬取 seed 中得地址,依次爬取完成后,程序即结束。而守护进程模式需要另外开启队列(内存队列、Redis 队列等),但拥有更多的功能,如可以自动发现页面中的链接加入队列,循环爬取。以下是守护进程模式下的说明。
*启动*
```
// 启动爬虫,开启所有爬虫进程
$ php start.php start
```
*停止*
```
// 停止爬虫,关闭所有爬虫进程
php start.php stop
```
*清理*
```
// 删除日志文件,清空队列信息
php start.php clean
```
<p class="danger">
在守护模式中,如果需要使用数据库、redis 等连接,需要在各种回调函数中建立连接,否则可能会发生意想不到的错误。<br>
建议使用单例模式,并在 [startWorker](#startworker) 中关闭之前建立的连接。
</p>
### 例子
#### 例子一
爬取糗事百科热门列表页,采用守护进程模式。在开始爬取前,我们需要一个队列,在这里使用框架中带有的内存队列。
首先建立一个队列文件 queue.php,写入下列内容
``` php
<?php
require_once(__DIR__ . '/vendor/autoload.php');
// 启动队列
\Beanbun\Queue\MemoryQueue::server();
```
建立爬虫文件 start.php,写入下列内容
``` php
<?php
use Beanbun\Beanbun;
use Beanbun\Lib\Helper;
require_once(__DIR__ . '/vendor/autoload.php');
$beanbun = new Beanbun;
$beanbun->name = 'qiubai';
$beanbun->count = 5;
$beanbun->seed = 'http://www.qiushibaike.com/';
$beanbun->max = 30;
$beanbun->logFile = __DIR__ . '/qiubai_access.log';
$beanbun->urlFilter = [
'/https:\/\/siteproxy.ruqli.workers.dev:443\/http\/www.qiushibaike.com\/8hr\/page\/(\d*)\?s=(\d*)/'
];
// 设置队列
$beanbun->setQueue('memory', [
'host' => '127.0.0.1',
'port' => '2207'
]);
$beanbun->afterDownloadPage = function($beanbun) {
file_put_contents(__DIR__ . '/' . md5($beanbun->url), $beanbun->page);
};
$beanbun->start();
```
接下来在命令行中执行
```
$ php queue.php start
$ php start.php start
```
先启动队列进程,再启动爬虫。
## Beanbun 类
### 属性
Beanbun 对象实例化后,可以对对象的一些属性进行设置,这样爬虫爬取网页时,就会按照这些设置进行爬取。
#### name
<p class="tip">
定义当前爬虫名称,string 类型,可选设置。
</p>
示例
``` php
$beanbun->name = 'demo';
```
#### daemonize
<p class="tip">
定义当前爬虫运行方式,bool 类型,可选设置。<br>
true 为守护进程模式,false 为普通模式。<br>
CLI 模式下默认为 true,http请求下或CLI模式下没有`start`参数,默认为 false。
</p>
示例
``` php
$beanbun->daemonize = false;
```
#### count
<p class="tip">
定义当前爬虫进程数,仅守护进程模式下有效。int 类型,可选设置,默认为 5。
</p>
示例
``` php
$beanbun->count = 10;
```
#### seed
<p class="tip">
定义爬虫入口,string 或 array 类型,必选设置。
</p>
示例
``` php
$beanbun->seed = 'http://www.950.com/';
// or
$beanbun->seed = [
'http://www.950d.com/',
'http://www.950d.com/list-1.html',
[
'http://www.950d.com/list-2.html',
[
'timeout' => 10,
'headers' => [
'user-agent' => 'beanbun-spider',
]
]
]
];
```
#### urlFilter
<p class="tip">
定义当前爬取网页url的正则表达式,符合表达式规则的 url 才会被加入队列,
array 类型,可选设置。
</p>
示例
``` php
$beanbun->urlFilter = [
'/https:\/\/siteproxy.ruqli.workers.dev:443\/http\/www.950d.com\/list-(\d*).html/'
];
```
#### max
<p class="tip">
定义当前爬虫最大抓取网页数量,如抓取达到此数则停止抓取,为0时不限制抓取数量,默认为0。int 类型,可选设置。<br>
</p>
示例
``` php
$beanbun->max = 100;
```
#### interval
<p class="tip">
定义当前每个爬虫进程抓取网页的间隔时间,默认为1,最低为0.01。double 类型,可选设置。<br>
</p>
示例
``` php
$beanbun->interval = 0.1;
```
#### timeout
<p class="tip">
定义爬虫全局下载单个网页超时时间,单位为秒,默认为5秒。int 类型,可选设置。<br>
如果为单个网页单独设置了超时时间(如在 options 内),则覆盖此项。
</p>
示例
``` php
$beanbun->timeout = 10;
```
#### userAgent
<p class="tip">
定义爬虫全局下载单个网页 user-agent 属性,string 类型,可选设置。<br>
`pc`时随机生成 PC 浏览器 user-agent,<br>
`ios`时随机生成 iOS 浏览器 user-agent,<br>
`android`时随机生成 android 浏览器 user-agent,<br>
`mobile`时随机生成 iOS 或 android 浏览器 user-agent,<br>
默认值为`pc`,如不为以上值,则直接使用定义值。如果为单个网页单独设置了 user-agent(如在 options 内),则覆盖此项。
</p>
示例
``` php
$beanbun->userAgent = 'ios';
// or
$beanbun->userAgent = 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:29.0) Gecko/20100101 Firefox/29.0';
```
#### logFile
<p class="tip">
定义当前爬虫日志文件路径,仅守护进程模式下有效。string 类型,可选设置。
</p>
示例
``` php
$beanbun->logFile = __DIR__ . '/beanbun_access.log';
```
#### hooks
<p class="tip">
定义爬虫执行钩子,也是爬虫每次爬取网页的执行顺序。array 类型,可选设置。<br>
默认为['startWorkerHooks', 'beforeDownloadPageHooks', 'downloadPageHooks', 'afterDownloadPageHooks', 'discoverUrlHooks', 'afterDiscoverHooks', 'stopWorkerHooks',
]
</p>
示例
``` php
$beanbun->hooks = [
'startWorkerHooks',
'beforeDownloadPageHooks',
'downloadPageHooks',
'afterDownloadPageHooks',
'discoverUrlHooks',
'afterDiscoverHooks',
'customHooks',
'stopWorkerHooks',
];
```
#### id
<p class="tip">
返回当前爬虫进程id,int 类型
</p>
示例
``` php
// 下载页面后写一条日志,记录进程下载页面成功
$beanbun->afterDownloadPage