从零开始写Python爬虫 --- 2.4 爬虫实践:代理的爬取和验证

爬网站的时候,由于各种原因,ip被锁了,这个时候我们就需要通过代理来突破封锁。网上有很多代理网站,付费和免费的都有,这次我们就来写一个scrapy爬虫,爬一些免费的代理下来用。

目标分析:

本次爬取了代理网站:

大象代理:HTTP免费HTTP代理IP_HTTP快代理:快代理 - 高速http代理ip每天更新

目标很简单,从网上爬下ip地址和端口,保存在本地文件中

数据筛选:

相信写了这么多个demo,大家对于从html文件中定位元素位置都不陌生了吧?我这里就不写具体是怎么抓的了,大家可以用自己的喜欢的方法,无论是Xpath还是CSS选贼器,或者是我们原来用的最顺手的bs4

如果还是无从下手,可以回头看看我bs4爬虫的教程,看看我是如何做的其实最重要的就是两点:

掌握选择器语法熟练使用chrome开发工具

要是还是一点头绪都没有,可以之间看我下面实现的代码。

项目的创建:

这一部分很简单,就是套路东西,我也不详细说啦,跟着代码来就行:

# 创建项目 scrapy startproject proxy # c进入项目文件夹 cd proxy # 创建xici代理爬虫 scrapy genspider dxdlspider xicidaili.com # 创建快代理爬虫 scray genspider kdlspider kuaidaili.com # 看看目录长啥样 . ├── proxy │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-36.pyc │ │ ├── items.cpython-36.pyc │ │ ├── pipelines.cpython-36.pyc │ │ └── settings.cpython-36.pyc │ ├── items.py │ ├── middlewares.py │ ├── pipelines.py │ ├── settings.py │ └── spiders │ ├── __init__.py │ ├── __pycache__ │ │ ├── __init__.cpython-36.pyc │ │ ├── dxdlspider.cpython-36.pyc │ │ └── kdlspider.cpython-36.pyc │ ├── dxdlspider.py │ └── kdlspider.py └── scrapy.cfg 4 directories, 16 files

items的编写:

由于我们只需要代理的端口和ip,网页上其他花里胡哨的东西都不要,所以items编写起来异常的简单:

import scrapy class ProxyItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() #这个爬虫十分简单,我们要ip+端口,所以一个字段就够用了! addr = scrapy.Field()

Spider的编写:

我又要来唠叨了,这个部分还是我们scrapy框架中的核心部分!虽然在这个例子里非常的简单:

编写大象代理的Spider:

在编写这个Spider的时候,我吃惊的发现,该站张居然提供了代理的apiapi:http://api.xicidaili.com/free2016.txt这也就意味着,我们不用辛苦的写代码筛选数据了,但是我们已经把爬虫建立了,总不能删了吧?那多难受!这个简单,我们把Response.text的内容传给item好! 就这样做:

import scrapy from proxy.items import ProxyItem class DxdlspiderSpider(scrapy.Spider): name = "dxdlspider" allowed_domains = ["xicidaili.com"] start_urls = [] def parse(self, response): item = ProxyItem() #因为直接调用网站的api,本身get下来的就是一个text文本, #我们直接把文本传给item再交给pipeline处理就行 item[addr] = response.text return item 编写快代理的Spider:

这个网站就没有上一个那么好了,我们老老实实自己爬吧:

import scrapy from proxy.items import ProxyItem class KdlspiderSpider(scrapy.Spider): name = "kdlspider" allowed_domains = ["kuaidaili.com"] start_urls = [] # 通过简单的循环,来生成爬取页面的列表 # 这里我们爬1~5页 for i in range(1, 6): start_urls.append( + str(i) + /) def parse(self, response): # 我们先实例化一个item item = ProxyItem() # 通过Xpath找到每条代理的内容 mian = response.xpath( //table[@class="table table-bordered table-striped"]/tbody/tr) for li in mian: #找到ip地址 ip = li.xpath(td/text()).extract()[0] #找到端口: port =li.xpath(td/text()).extract()[1] #将两者连接,并返回给item处理 item[addr] = ip+:+port yield item

PIPELINE的编写:

最核心和最难的爬虫部分写完了,剩下的就是收尾工作,我们来写个PIPELINE来爬到的数据写入本地。

但是这里需要注意一下,

我们这里有两个Spider,都会往pipeline里传item那么我们怎么分别处理呢?我查阅了一下文档,发现并没有什么特别好的解决方式,所以我就在pipeline里自己做了一个判断,看代码吧:

class ProxyPipeline(object): 这里我们通过对spider name的判断 来分清楚item是哪一个spider传来的 从而做出不同的处理方式 def process_item(self, item, spider): if spider.name == dxdlspider: content = item[addr].split(\r\n) for line in content: open(/Users/ehco/Desktop/result/dx_proxy.txt,a).write(line+\n) elif spider.name==kdlspider: #我们直接将传来的addr写入文本 open(/Users/ehco/Desktop/result/kdl_proxy.txt,a).write(item[addr]+\n) return item

测试一下:

啥? 为啥报错了? 这两个网站都不存在登录,所以就不是cookie的问题那么问题出在哪呢?经过我仔细周密的检查,我发现,原来是快代理有反爬虫机制:

请求过于频繁的时候,禁止访问!上有政策,下有对策,

我们来设置一下载延迟:

DOWNLOAD_DELAY = 1

编写配置文件Settings:

BOT_NAME = proxy SPIDER_MODULES = [proxy.spiders] NEWSPIDER_MODULE = proxy.spiders ROBOTSTXT_OBEY = True # 设置下载延迟,避免被封锁 DOWNLOAD_DELAY = 1 ITEM_PIPELINES = { proxy.pipelines.ProxyPipeline: 300, }

到这里,我们的功能就完全写好了

代理爬到了,

剩下的就是筛选工作了。

筛选无用代理:

网上充斥着大量的代理,但

无论是免费的还是付费的其实质量都很堪忧,

所以虽然我们从网上将代理爬了下来,

如何保证这些代理都是好用的呢?

本来我们可以把验证的过程写在PIPELINE里,可是验证一个代理有效性的时机间,比把数据写到本地长了十几倍,所以我决定写一个脚本来筛选代理。

这个脚本会用到一点多线程的知识,

说实在的,Python对于多线程和多进程的支持有点差原来我也从来没有这方面的需求,所以就一直没在意这方面这次用到了,我也是仔细学习了一下,

下面推荐一份比较好的多线程并发材料:一行 Python 实现并行化 -- 日常多线程操作的新思路

不多说了,看代码吧:

我们通过这个小脚本来判断 抓取到的ip代理是否可以用! 还是通过我最熟悉的request库来实现 不过这里稍微加一下我也不太熟悉的多线程 import requests # 引入这个库来获得map函数的并发版本 from multiprocessing.dummy import Pool as ThreadPool # 定义全局变量 dir_path = /Users/ehco/Desktop/result/ alive_ip = [] # 使得map并发!实例化pool对象 pool = ThreadPool() # 设置并发数量! pool = ThreadPool(20) def test_alive(proxy): 一个简单的函数, 来判断通过代理访问百度 筛选通过的代理保存到alive_ip中 global alive_ip #设置代理头 proxies = {http: proxy} print(正在测试:{}.format(proxies)) try: r = requests.get(http://www.baidu.com, proxies=proxies, timeout=3) if r.status_code == 200: print(该代理:{}成功存活.format(proxy)) alive_ip.append(proxy) except: print(该代理{}失效!.format(proxies)) def Out_file(alive_ip=[]): 将符合要求的代理写入文件 global dir_path with open(dir_path + alive_ip.txt, a+) as f: for ip in alive_ip: f.write(ip + \n) print(所有存活ip都已经写入文件!) def test(filename=blank.txt): # 循环处理每行文件 with open(dir_path + filename, r) as f: lines = f.readlines() # 我们去掉lines每一项后面的\n\r之类的空格 # 生成一个新的列表! proxys = list(map(lambda x: x.strip(), [y for y in lines])) #一行代码解决多线程! pool.map(test_alive,proxys) # 将存活的ip写入文件 Out_file(alive_ip) #调用函数! test(1.txt) 代理爬取结果:

因为还没到用代理的时候,我先爬取少量的:

筛选结果展示:

一共爬下来快200个,能用的就这么点,可怜吧~

这几天我不是消失了,实在是比较忙,期末到了,各种大作业(ㄒoㄒ) 加上突发奇想,想把妹子图全站趴下来,就又浪费了一点时间。但是放心,我不会烂尾的 逃~

先放两张我爬妹子图的成果:

一共3347个图包,打包一共10g

想要资源的同学关注一下

:findyourownway 回复: 妹纸图

里还有免费分享的ss线路,习惯在Google查资料的小伙伴也可以关注一波!

每天的学习记录都会 同步更新到:微信: findyourownway知乎专栏:从零开始写Python爬虫 - 知乎专栏blog : www.ehcoblog.mlGithub: Ehco1996/Python-crawler