Python+Docker+Redis-实现分布式爬取阳光问政

2023-11-02

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认为不需要分布式,就随机一个来执行爬虫

如何解决?

  将代码改造成广度优先模式即可

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Python+Docker+Redis-实现分布式爬取阳光问政 的相关文章

随机推荐