sun-political
一、编写爬虫代码
1.创建项目
pip install scrapy scrapy-redis -i https://pypi.tuna.tsinghua.edu.cn/simple
scrapy startproject sun
2.创建爬虫
scrapy genspider -t crawl political wz.sun0769.com
3.编写setting.py
ROBOTSTXT_OBEY = False
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) ' \
'AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3947.100 Safari/537.36'
DOWNLOAD_DELAY = 3
##### 增加 Scrapy-Redis 组件的配置
###### (必须)使用 Scrapy-Redis 的调度器,在 Redis 中分配请求
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
###### (必须)使用 Scrapy-Redis 的去重组件,在 Redis 数据库中做去重
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
###### (必须)允许爬虫出现暂停和暂停后恢复,也就是说不清理 Redis 队列
SCHEDULER_PERSIST = True
###### (必须)指定连接 Redis 数据库IP地址
REDIS_HOST = '192.168.0.101' # 这里需要换成你本地主机的IP
###### (必须)指定连接 Redis 数据库端口号
REDIS_PORT = 6378
###### (必须) 通过配置 RedisPipeline 将 Item 写入 key 为 sidper.name:items 的 Redis 的list 中,以便后面的分布式处理 Item,这个已经由 Scrapy-Redis 实现。
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 300
}
4.编写items.py
no = scrapy.Field() # 编号
title = scrapy.Field() # 标题
content = scrapy.Field() # 内容
5.编写political.py
import scrapy
from scrapy.linkextractors import LinkExtractor
from scrapy.spiders import CrawlSpider, Rule
from scrapy_redis.spiders import RedisCrawlSpider
from sun.items import SunItem
import urllib.parse
class PoliticalSpider(RedisCrawlSpider):
name = 'political'
allowed_domains = ['wz.sun0769.com']
# start_urls = ['http://wz.sun0769.com/political/index/politicsNewest?id=1&page=1']
redis_key = "Political:start_urls"
rules = (
Rule(LinkExtractor(allow=r'id=1&page=\d+'), callback='parse_item', follow=True),
)
def parse_item(self, response):
node_li = response.xpath('//ul[@class="title-state-ul"]/li')
for li in node_li:
no = li.xpath('./span[@class="state1"]/text()').extract_first()
title = li.xpath('./span[@class="state3"]/a/text()').extract_first()
detail_href = li.xpath('./span[@class="state3"]/a/@href').extract_first()
full_detail_href = urllib.parse.urljoin(response.url, detail_href)
# print(full_detail_href)
item = SunItem()
item['no'] = no
item['title'] = title
yield scrapy.Request(full_detail_href, callback=self.parse_detail, meta={"data": item})
def parse_detail(self, response):
item = response.meta['data']
item['content'] = response.xpath('//div[@class="details-box"]/pre/text()').extract_first()
return item
二、打包代码,制作docker镜像
1.创建并编写Dockerfile文件
FROM python:3.7
ADD . /wz
WORKDIR /wz
RUN pip install scrapy scrapy-redis -i https://pypi.tuna.tsinghua.edu.cn/simple
WORKDIR /wz/sun
CMD scrapy crawl political
2.创建并编写.dockerignore文件
.idea
venv
三、通过Docker Compose搭建容器
1.创建并编写docker-compose.yml文件
spider:
built: .
volumes:
- .: /wz
links:
-redis
redis:
images:redis
ports:
- "6378:6379"
四、部署服务
1.启动容器
docker-compose up
2.扩展spider服务(在docker-compose.yml文件所在目录)
cd E:\PCProject\zuoye
docker-compose scale spider=4
五、执行爬虫
进入redis容器里面发布初始url
docker exec -it zuoye_redis_1 /bin/bash
redis-cli
lpush Political:start_urls http://wz.sun0769.com/political/index/politicsNewest?id=1&page=1
总结
分布式爬取网页的步骤总共分为五个步骤:
1.编写爬虫
编写爬虫代码时特别注意的是setting的配置,需要增加scrapy-redis组件的配置
SCHEDULER = "scrapy_redis.scheduler.Scheduler"(使用 Scrapy-Redis 的调度器,在 Redis 中分配请求)
DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"(使用 Scrapy-Redis 的去重组件,在 Redis 数据库中做去重)
SCHEDULER_PERSIST = True(允许爬虫出现暂停和暂停后恢复,也就是说不清理 Redis 队列)
REDIS_HOST = '192.168.0.101'(指定连接 Redis 数据库IP地址 填写自己本机的ip)
REDIS_PORT = 6378 (指定连接 Redis 数据库端口号 可以任意指定与别的服务不冲突的端口)
ITEM_PIPELINES = {
'scrapy_redis.pipelines.RedisPipeline': 300
}(通过配置 RedisPipeline 将 Item 写入 key 为 sidper.name:items 的 Redis 的list 中,以便后面的分布式处理 Item,这个已经由 Scrapy-Redis 实现。)
相关配置详情可以参考:https://github.com/rmax/scrapy-redis
爬虫代码跟普通爬虫是一样的,可以先写一个可以运行的普通爬虫,然后在此基础上进行修改,从而实现分布式爬取。
(要注意的就是:spider类不再继承CrawlSpider类,而是继承scrpy-redis下的RedisCrawlSpider类;
爬虫代码中不再需要start_urls,需要添加 redis_key 用来redis发布初始url指令)
2.打包爬虫代码,制作docker镜像
Dockerfile文件
3.通过docker-compose创建容器,搭建微服务架构
docker-compose.yml文件
ports:
- "xxxx:6379"
这里要注意创建redis容器时的端口xxxx要与setting文件里面定义的REDIS_PORT一致
4.部署环境
(注意执行位置,要在docker-compose.yml所在的路径下)
启动容器 docker-compose up
扩展spider服务:docker-compose scale spider=x
5.执行爬虫代码
进入redis容器,发布初始url指令来执行爬虫 : lpush redis_key url (redis_key为爬虫代码中定义的值)
遇到的问题
执行爬虫之后只会随机一个spider在工作,并没有实现分布式爬取,并且数据库中也会缺少request的列表。导致这个问题的原因是什么呢?
是因为此时的代码是深度优先模式。阳光问政这个页面,爬取的时候是爬完一页才能爬取下一页,request请求此时是不变的,只有一个,所以spider认为不需要分布式,就随机一个来执行爬虫
如何解决?
将代码改造成广度优先模式即可