Scrapy是一个用于爬取网站并提取结构化数据的应用程序框架,可用于各种有用的应用程序,例如数据挖掘,信息处理或历史档案。本文主要描述从某IP代理网站抓取内容的代码示例,免费代理IP时效性很差,仅供大家学习试用。
centos7安装Scrapy
pip install Scrapy
我本机安装时,不幸发生错误(Microsoft Visual C++ 14.0 is required),转而使用whl文件安装,下载地址【https://www.lfd.uci.edu/~gohlke/pythonlibs/】
分别下载Twisted和Scrapy,Twisted是依赖包,也需要安装。注意操作系统版本。
pip install Twisted-20.3.0-cp38-cp38-win_amd64.whl
pip install Scrapy-2.1.0-py3-none-any.whl
创建项目
scrapy startproject ipproxys
创建项目文件结构和主要文件的作用,如下:
scrapy.cfg :项目的配置文件
ipproxys/ :项目的Python模块
ipproxys/items.py :项目的目标文件,将抓取内容模型化
ipproxys/pipelines.py :项目的管道文件
ipproxys/settings.py :项目的设置文件
ipproxys/spiders/ :存储具体爬虫代码的目录
编写items.py代码
在items文件中增加目标网页对应的类,继承Item类,数据项是Field类型
class IpProxyItem(scrapy.Item):
# define the fields for your item here like:
ip = scrapy.Field()
port = scrapy.Field()
# 匿名度
anons = scrapy.Field()
# 类型:http/https
schema = scrapy.Field()
# 国家
country = scrapy.Field()
# 位置
position = scrapy.Field()
# 响应速度
speed = scrapy.Field()
# 最后验证时间
verify_time = scrapy.Field()
编写爬虫代码
在spiders目录下,新建jiangxianli_spider.py并编写爬虫类文件,继承scrapy.Spider类,实现start_requests和parse两个方法。
class JxlIpSpider(scrapy.Spider):
"""
搜索免费代理IP地址
"""
# Spider 的标识符,用于唯一标识该 Spider;在整个项目中是全局唯一的
name = "free_ip"
def start_requests(self):
"""
必须定义并返回一组可以被 Spider 爬取的 Requests,Request 对象由一个 URL 和一个回调函数构成
:return:
"""
urls = [
'https://ip.jiangxianli.com/?page=1',
'https://ip.jiangxianli.com/?page=2'
# 'https://www.kuaidaili.com/free' # 国内高匿IP
]
for url in urls:
yield scrapy.Request(url=url, callback=self.parse)
def parse(self, response):
"""
Request 对象中的回调方法,用来解析request返回的内容
:param response:
:return:
"""
self.logger.info('正在爬取:< ' + response.request.url + ' >')
# 按行读取数据
tr_list = response.css("div.layui-form>table>tbody>tr")
for tr in tr_list:
# css的伪类 ::text
ip = tr.css('td:nth-child(1)::text').get()
port = tr.css('td:nth-child(2)::text').get()
anons = tr.css('td:nth-child(3)::text').get()
schema = tr.css('td:nth-child(4)::text').get()
position = tr.css('td:nth-child(5)::text').get()
country = tr.css('td:nth-child(6)::text').get()
# 7 运营商
speed = tr.css('td:nth-child(8)::text').get()
# 9 存活时间
verify_time = tr.css('td:nth-child(10)::text').get()
item = IpProxyItem()
item['ip'] = ip
item['port'] = port
item['anons'] = anons
item['schema'] = schema
item['position'] = position
item['country'] = country
item['schema'] = schema
item['speed'] = speed
item['verify_time'] = verify_time
print(item)
yield item
注意点:
- name :标识蜘蛛. 它在一个项目中必须是唯一的,也就是说,不能为不同的Spider设置相同的名称.
- start_requests() :必须返回一个可迭代的Requests(您可以返回请求列表或编写生成器函数),Spider将开始从中进行爬网. 随后的请求将从这些初始请求中依次生成.
- parse() :将被调用以处理为每个请求下载的响应的方法. response参数是TextResponse一个实例,该实例保存页面内容并具有其他有用的方法来处理它.
编写pipe保存数据
在piplelines.py文件中编写代码,将数据保存到redis库中。
同时,切记在配置文件中进行配置。
# 使用 connection pool 来管理对一个 redis server 的所有连接,避免每次建立、释放连接的开销
redis_pool = redis.ConnectionPool(host='192.168.xx.xx', port=6379, decode_responses=True, password='your password')
class IpProxyPipeline:
def process_item(self, item, spider):
self.save_redis(item)
return item
def save_redis(self, item):
"""
redis 提供两个类 Redis 和 StrictRedis, StrictRedis 用于实现大部分官方的命令,Redis 是 StrictRedis 的子类,用于向后兼用旧版本。
redis 取出的结果默认是字节,我们可以设定 decode_responses=True 改成字符串
:return:
"""
# 从连接池获取
redis_server1 = redis.StrictRedis(connection_pool=redis_pool)
# 直接创建连接
# redis_server2 = redis.StrictRedis(host='192.168.xx.xx', port=6379, password='your password')
# redis cache, push类似list.append
redis_server1.rpush('iplist', '{}://{}:{}'.format(item['schema'].lower(), item['ip'], item['port']))
配置pipe
# Configure item pipelines
ITEM_PIPELINES = {
'ipproxys.pipelines.IpProxyPipeline': 300,
}
运行项目
按蜘蛛名称运行
scrapy crawl free_ip
也可以按文件运行:scrapy runspider <spider_file.py>
附录:试用代理
url = 'https://www.baidu.com'
# 从redis获取代理ip列表,循环试用
for i in range(redis_server1.llen('iplist')):
ip_proxy = redis_server1.lindex('iplist', i)
# 区分http和https,如果拆分为两个key,则更方便一些
schame = 'http' if url.find(':') == 5 else 'https'
if schame == ip_proxy[0:5]:
proxies[schame] = ip_proxy
try:
# 超时分为连接超时和读取超时
res = requests.get(url=url, proxies=proxies, timeout=(5, 20))
if res.status_code == 200:
print('ok')
break
except Exception as ex:
print(ex)