上一章节我们讲完了自动加载,现在我们正式进入爬虫核心代码的编写中,首先我们需要先看看整个目录
config.php 这个是我们的配置文件加载文件
ProxyPool.php 这个是爬虫的核心处理文件
Queue.php 这个是队列操作的处理文件
Requests.php 这个是发起请求的处理文件
然后我们在回忆一下入口文件的代码
<?php require_once __DIR__ . '/autoloader.php'; require_once __DIR__ . '/vendor/autoload.php'; use ProxyPool\core\ProxyPool; $proxy = new ProxyPool(); $proxy->run();
通过这里可以看到我们使用了core里面ProxyPool的run方法,先来看看ProxyPool的内容吧
<?php use ProxyPool\core\Requests; //HTTP请求文件 use ProxyPool\core\Queue; //队列操作文件 class ProxyPool { private $redis; private $httpClient; private $queueObj; function __construct() { $redis = new \Redis(); $redis->connect(config("database.redis_host"), config("database.redis_port")); $this->redis = $redis;$this->httpClient = new Requests(['timeout' => 10]); $this->queueObj = new Queue(); } public function run() { echo "start to spider ip...." . PHP_EOL; $ip_arr = $this->get_ip(); //获取IP的具体方法 echo "select IP num: " . count($ip_arr) . PHP_EOL; echo "start to check ip...." . PHP_EOL; $this->check_ip($ip_arr); //验证IP可用性的方法 $ip_pool = $this->redis->smembers('ip_pool'); //读取redis中的ip echo "end check ip...." . PHP_EOL; print_r($ip_pool); //输出ip数组 die; } }
其中get_ip方法会爬取两个网站的IP
//获取各大网站代理IP private function get_ip() { $ip_arr = []; $ip_arr = $this->get_xici_ip($ip_arr); //西刺代理 $ip_arr = $this->get_kuaidaili_ip($ip_arr); //快代理 return $ip_arr; }
我们先来来看看西刺代理的爬取
private function get_xici_ip($ip_arr) { for ($i = 1; $i <= config('spider.page_num'); $i++) { list($infoRes, $msg) = $this->httpClient ->request('GET','http://www.xicidaili.com/nn/'.$i,[]); if (!$infoRes) { print_r($msg); //输出错误信息 exit(); } $infoContent = $infoRes->getBody(); $this->convert_encoding($infoContent); preg_match_all('/<tr.*>[\s\S]*?<td class="country">[\s\S]*?<\/td>[\s\S]*?<td>(.*?)<\/td>[\s\S]*?<td>(.*?)<\/td>/', $infoContent, $match); $host_arr = $match[1]; $port_arr = $match[2]; foreach ($host_arr as $key => $value) { $ip_arr[] = $host_arr[$key].":".$port_arr[$key]; } } return $ip_arr; }
这个方法里面,我们首先使用 config('spider.page_num') 这个方法读取了配置文件里面定义的爬取页数,我这里定义的是3页,然后我们打开西刺代理的网站,会发现域名是
http://www.xicidaili.com/nn/XX 这个XX是第几页,第一页就是1,第二页就是2,以此类推
所以我们在代码里面循环访问了三次网站,获取到网页的返回值,然后用正则匹配html去获取里面的地址和端口号(具体html元素可以在网站右键点击审查元素查看)
preg_match_all('/<tr.*>[\s\S]*?<td class="country">[\s\S]*?<\/td>[\s\S]*?<td>(.*?)<\/td>[\s\S]*?<td>(.*?)<\/td>/', $infoContent, $match);
然后经过一些处理,将获取到的IP返回。这就是get_xici_ip这个方法做的事情,它就是负责爬取IP。
然后我们来看看
//检测IP可用性 private function check_ip($ip_arr) { $this->queueObj = $this->queueObj->arr2queue($ip_arr); $queue = $this->queueObj->getQueue(); foreach ($queue as $key => $value) { //用百度网和腾讯网测试IP地址的可用性 for ($i=0; $i < config('spider.examine_round'); $i++) { $response = $this->httpClient->test_request('GET','https://www.baidu.com', ['proxy' => 'https://'.$value]); if (!$response) { $response = $this->httpClient->test_request('GET','http://www.qq.com', ['proxy' => 'http://'.$value]); if ($response && $response->getStatusCode() == 200) { break; } } else if($response->getStatusCode() == 200) { break; } } //将结果存入redis if ($response && $response->getStatusCode() == 200) { $this->set_ip2redis($value); } else{ echo $value . " error... ". PHP_EOL; } } }
这里我们使用了https的百度和http的qq来检测,如果成功访问就把这个IP插入redis中。
这样我们就能做到爬取IP并且校验可用性了。