scrapy

scrapy

scrapy官方文档

https://scrapy-chs.readthedocs.io/zh_CN/0.24/index.html

scrapy的概念

Scrapy是一个Python编写的开源网络爬虫框架。它是一个被设计用于爬取网络数据、提取结构性数据的框架。

Scrapy 使用了Twisted[‘twɪstɪd]异步网络框架,可以加快我们的下载速度。
Scrapy文档地址:http://scrapy-chs.readthedocs.io/zh_CN/1.0/intro/overview.html

scrapy框架的作用

少量的代码,就能够快速的抓取

scrapy的工作流程

回顾之前的爬虫流程

上面的流程可以改写为

scrapy的流程


其流程可以描述如下:

  1. 爬虫中起始的url构造成request对象–>爬虫中间件–>引擎–>调度器
  2. 调度器把request–>引擎–>下载中间件—>下载器
  • 下载器发送请求,获取response响应—>下载中间件—>引擎—>爬虫中间件—>爬虫
  1. 爬虫提取url地址,组装成request对象—->爬虫中间件—>引擎—>调度器,重复步骤2
  2. 爬虫提取数据—>引擎—>管道处理和保存数据

注意:

  1. 图中中文是为了方便理解后加上去的
  2. 图中绿色线条的表示数据的传递
  3. 注意图中中间件的位置,决定了其作用
  4. 注意其中引擎的位置,所有的模块之前相互独立,只和引擎进行交互

scrapy的三个内置对象

  • request请求对象:由url method post_data headers等构成
  • response响应对象:由url body status headers等构成
  • item数据对象:本质是个字典

scrapy中每个模块的具体作用

注意:

  • 爬虫中间件和下载中间件只是运行逻辑的位置不同,作用是重复的:如替换UA等

scrapy的入门使用

安装scrapy

命令:
    sudo apt-get install scrapy
或者:
    pip/pip3 install scrapy

scrapy项目开发流程

  1. 创建项目:
    scrapy startproject mySpider
  2. 生成一个爬虫:
    scrapy genspider xywx xywx.com
  3. 提取数据:
    根据网站结构在spider中实现数据采集相关内容
  4. 保存数据:
    使用pipeline进行数据后续处理和保存

创建项目

通过命令将scrapy项目的的文件生成出来,后续步骤都是在项目文件中进行相关操作
创建scrapy项目的命令:
    scrapy startproject <项目名字>
示例:
    scrapy startproject myspider

生成的目录和文件结果如下:

创建爬虫

通过命令创建出爬虫文件,爬虫文件为主要的代码作业文件,通常一个网站的爬取动作都会在爬虫文件中进行编写。

命令:
    在项目路径下执行:
    scrapy genspider <爬虫名字> <允许爬取的域名>
爬虫名字: 作为爬虫运行时的参数

允许爬取的域名: 为对于爬虫设置的爬取范围,设置之后用于过滤要爬取的url,如果爬取的url与允许的域不通则被过滤掉。

示例:

    cd myspider
    scrapy genspider xywy  xywy.com

完善爬虫

在/myspider/myspider/spiders/xywx.py中修改内容如下:

import scrapy
from myspider.items import MyspiderItem
from  copy import deepcopy

class XywySpider(scrapy.Spider):
    name = 'xywy'
    allowed_domains = ['xywy.com'] # 允许爬取的范围
    start_urls = ['http://jib.xywy.com/'] # 开始爬取的url地址

    def parse(self, response):
        item = MyspiderItem()  # 实例化后可直接使用
        for page in range(1, 11000):
            try:
                item['id'] = page
                basic_url = 'http://jib.xywy.com/il_sii/gaishu/%s.htm' % page  ## 简介
                yield scrapy.Request(basic_url, callback=self.parse_basic_url, meta={"item": deepcopy(item)})
            except Exception as e:
                print(e, page)


    def parse_basic_url(self, response):
        """
        基本信息解析
        :param response:
        :return:
        """
        item = response.meta['item']
        title = response.xpath('//strong[@class="db f20 fYaHei fb jib-articl-tit tc pr"]/text()').extract_first()
        category = response.xpath('//div[@class="wrap mt10 nav-bar"]/a/text()')
        desc = response.xpath('//div[@class="jib-articl-con jib-lh-articl"]/p/text()').extract_first().strip()
        ps = response.xpath('//div[@class="mt20 articl-know"]/p')

        infobox = []
        for p in ps:
            info = p.xpath('string(.)').extract_first().replace('\r', '').replace('\n', '').replace('\xa0', '').replace('   ', '').replace('\t', '')
            infobox.append(info)

        category_list = []
        for cate in category: ## 疾病分类, 多分类
            category_content = cate.extract().strip()
            if category_content and category_content != "疾病百科": ## 去掉不需要的分类
                category_list.append(cate.extract())
        basic_data = {}
        basic_data['category'] = category_list
        basic_data['name'] = title.split('简介')[0]
        basic_data['desc'] = desc
        basic_data['attributes'] = infobox
        item['basic'] = basic_data

        cause_url = 'http://jib.xywy.com/il_sii/cause/%s.htm' % item['id']  ## 原因
        yield scrapy.Request(cause_url, callback=self.parse_cause_url, meta={"item": deepcopy(item)})


    def parse_cause_url(self, response):
        item = response.meta['item']
        ps = response.xpath('//p')
        infobox = []
        for p in ps:
            info = p.xpath('string(.)').extract_first().replace('\r', '').replace('\n', '').replace('\xa0', '').replace('   ', '').replace('\t', '')
            if info:
                infobox.append(info)
        item['cause'] = '\n'.join(infobox)
        prevent_url = 'http://jib.xywy.com/il_sii/prevent/%s.htm' % item['id']  ##治疗
        yield scrapy.Request(prevent_url, callback=self.parse_prevent_url, meta={"item": deepcopy(item)})


    def parse_prevent_url(self, response):
        item = response.meta['item']
        ps = response.xpath('//p')
        infobox = []
        for p in ps:
            info = p.xpath('string(.)').extract_first().replace('\r', '').replace('\n', '').replace('\xa0', '').replace('   ', '').replace('\t', '')
            if info:
                infobox.append(info)
        item['prevent'] = '\n'.join(infobox)

        symptom_url = 'http://jib.xywy.com/il_sii/symptom/%s.htm' % item['id']  ##
        yield scrapy.Request(symptom_url, callback=self.parse_symptom_url, meta={"item": deepcopy(item)})


    def parse_symptom_url(self, response):
        item = response.meta['item']
        symptoms = response.xpath('//a[@class="gre" ]/text()').extract_first()
        ps = response.xpath('//p')
        detail = []
        for p in ps:
            info = p.xpath('string(.)').extract_first().replace('\r', '').replace('\n', '').replace('\xa0', '').replace('   ', '').replace('\t', '')
            detail.append(info)
        symptoms_data = {}
        symptoms_data['symptoms'] = symptoms
        symptoms_data['symptoms_detail'] = detail
        item['symptom'] = symptoms_data
        inspect_url = 'http://jib.xywy.com/il_sii/inspect/%s.htm' % item['id']  ##
        yield scrapy.Request(inspect_url, callback=self.parse_inspect_url, meta={"item": deepcopy(item)})


    def parse_inspect_url(self, response):
        item = response.meta['item']
        inspects = response.xpath('//li[@class="check-item"]/a/@href').extract_first()
        item['inspect'] = inspects
        treat_url = 'http://jib.xywy.com/il_sii/treat/%s.htm' % item['id']  ## 治疗
        yield scrapy.Request(treat_url, callback=self.parse_treat_url, meta={"item": deepcopy(item)})


    def parse_treat_url(self, response):
        item = response.meta['item']
        ps = response.xpath('//div[starts-with(@class,"mt20 articl-know")]/p')
        infobox = []
        for p in ps:
            info = p.xpath('string(.)').extract_first().replace('\r', '').replace('\n', '').replace('\xa0', '').replace('   ', '').replace('\t', '')
            infobox.append(info)
        item['treat'] = infobox

        food_url = 'http://jib.xywy.com/il_sii/food/%s.htm' % item['id']  ## 食物
        yield scrapy.Request(food_url, callback=self.parse_food_url, meta={"item": deepcopy(item)})


    def parse_food_url(self, response):
        item = response.meta['item']
        divs = response.xpath('//div[@class="diet-img clearfix mt20"]')
        food_data = {}
        try:
            food_data['good'] = divs[0].xpath('./div/p/text()').extract_first()
            food_data['bad'] = divs[1].xpath('./div/p/text()').extract_first()
            food_data['recommand'] = divs[2].xpath('./div/p/text()').extract_first()
        except Exception as e:
            print("food" + str(e))
        item['food'] = food_data

        drug_url = 'http://jib.xywy.com/il_sii/drug/%s.htm' % item['id']  ## 药物

        yield scrapy.Request(drug_url, callback=self.parse_drug_url, meta={"item": deepcopy(item)})


    def parse_drug_url(self, response):
        item = response.meta['item']
        try:
            drugs = [i.replace('\n', '').replace('\t', '').replace(' ', '') for i in response.xpath('//div[@class="fl drug-pic-rec mr30"]/p/a/text()').extract()]
        except Exception as e:
            print("drup"+str(e))
        item['drug'] = drugs

        yield item

注意:

  • scrapy.Spider爬虫类中必须有名为parse的解析
  • 如果网站结构层次比较复杂,也可以自定义其他解析函数
  • 在解析函数中提取的url地址如果要发送请求,则必须属于allowed_domains范围内,但是start_urls中的url地址不受这个限制,我们会在后续的课程中学习如何在解析函数中构造发送请求
  • 启动爬虫的时候注意启动的位置,是在项目路径下启动
  • parse()函数中使用yield返回数据,注意:解析函数中的yield能够传递的对象只能是:BaseItem, Request, dict, None

定位元素以及提取数据、属性值的方法

解析并获取scrapy爬虫中的数据: 利用xpath规则字符串进行定位和提取

  1. response.xpath方法的返回结果是一个类似list的类型,其中包含的是selector对象,操作和列表一样,但是有一些额外的方法
  2. 额外方法extract():返回一个包含有字符串的列表
  3. 额外方法extract_first():返回列表中的第一个字符串,列表为空没有返回None

5.3 response响应对象的常用属性

  • response.url:当前响应的url地址
  • response.request.url:当前响应对应的请求的url地址
  • response.headers:响应头
  • response.requests.headers:当前响应的请求头
  • response.body:响应体,也就是html代码,byte类型
  • response.status:响应状态码

保存数据

利用管道pipeline来处理(保存)数据

在pipelines.py文件中定义对数据的操作

  1. 定义一个管道类
  2. 重写管道类的process_item方法
  3. 方法处理完item之后必须返回给引擎
import json

class xywxPipeline():
    # 爬虫文件中提取数据的方法每yield一次item,就会运行一次
    # 该方法为固定名称函数
    def process_item(self, item, spider):
        print(item)
        return item
import pymongo
from itemadapter import ItemAdapter
class MongoPipeline:
    collection_name = 'scrapy_items'
    def __init__(self, mongo_uri, mongo_db):
        self.mongo_uri = mongo_uri
        self.mongo_db = mongo_db
    @classmethod
    def from_crawler(cls, crawler):
        return cls(
            mongo_uri=crawler.settings.get('MONGO_URI'),
            mongo_db=crawler.settings.get('MONGO_DATABASE', 'items')
        )
    def open_spider(self, spider):
        self.client = pymongo.MongoClient(self.mongo_uri)
        self.db = self.client[self.mongo_db]
    def close_spider(self, spider):
        self.client.close()
    def process_item(self, item, spider):
         self.db[self.collection_name].
         insert_one(ItemAdapter(item).asdict())
          return item

在settings.py配置启用管道

ITEM_PIPELINES = {
    'myspider.pipelines.xywxPipeline': 400
}

Scrapy内置设置

## 分布式redis配置
# The download delay setting will honor only one of:
# 指定使用scrapy-redis的调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"

# 指定使用scrapy-redis的去重
DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter'
# 指定排序爬取地址时使用的队列,
# 默认的 按优先级排序(Scrapy默认),由sorted set实现的一种非FIFO、LIFO方式。
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderPriorityQueue'
# 可选的 按先进先出排序(FIFO)
# SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderQueue'
# 可选的 按后进先出排序(LIFO)
# SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderStack'
# 在redis中保持scrapy-redis用到的各个队列,从而允许暂停和暂停后恢复,也就是不清理redis queues
SCHEDULER_PERSIST = True

# 只在使用SpiderQueue或者SpiderStack是有效的参数,指定爬虫关闭的最大间隔时间
# SCHEDULER_IDLE_BEFORE_CLOSE = 10


# 通过配置RedisPipeline将item写入key为 spider.name : items 的redis的list中,供后面的分布式处理item
# 这个已经由 scrapy-redis 实现,不需要我们写代码
# ITEM_PIPELINES = {
#     #'distribute_country_tecah.pipelines.DistributeCountryPipeline':300,
#     'scrapy_redis.pipelines.RedisPipeline': 400
# }

# 指定redis数据库的连接参数
# REDIS_PASS是我自己加上的redis连接密码(默认不做)
REDIS_HOST = '192.168.124.129'
REDIS_PORT = 6379
REDIS_PARAMS ={
    'password': '123456',
    'db': 0
}
REDIS_ENCODING = 'utf-8'
# LOG等级
LOG_LEVEL = 'DEBUG'

#默认情况下,RFPDupeFilter只记录第一个重复请求。将DUPEFILTER_DEBUG设置为True会记录所有重复的请求。
DUPEFILTER_DEBUG =True

配置项中键为使用的管道类,管道类使用.进行分割,第一个为项目目录,第二个为文件,第三个为定义的管道类。
配置项中值为管道的使用顺序,设置的数值约小越优先执行,该值一般设置为1000以内。

运行scrapy

命令:在项目目录下执行scrapy crawl <爬虫名字>
示例:scrapy crawl xywx

文件选择

Scrapy.files.FilesPipeline
函数:

file_path: # 文件名通过url sha1加密

item_completed:  # 文件下载完成时候的操作

get_media_requests: # 取到settings配置的需要下载的url(是一个数组),循环请求。

inc_stats:  # 下载计数;

media_to_download: # 下载前检测

media_failed: # 下载失败说明

media_downloaded: # 下载主文件

file_downloaded: # 下载文件,被media_downloaded调用

示例:

class DownloadFilePipeline(FilesPipeline):
    # def __init__(self):
    #     super(DownloadFilePipeline, self).__init__()

    def item_completed(self, results, item, info):
        ## 默认文件为下载
        file_load_is_success = -1
        file_path = ""
        if "file_load_url" in item:
            file_load_is_success = 0
            for ok, value in results:
                ## 下载成功
                if ok == True:
                    file_load_is_success = 1
                    file_path = value["path"]
                else:
                    ## 下载失败
                    file_load_is_success = 0

        item["file_load_is_success"] = file_load_is_success
        item['file_path'] = file_path

        return item

Scrapy redis

scrapy-redis是分布式爬虫较通用简单的框架,我们都知道scrapy框架不支持分布式的,scrapy-redis是以redis为基础的组件。
settings设置

## 分布式redis配置
# The download delay setting will honor only one of:
# 指定使用scrapy-redis的调度器
SCHEDULER = "scrapy_redis.scheduler.Scheduler"
# 指定使用scrapy-redis的去重
DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter'
# 指定排序爬取地址时使用的队列,
# 默认的 按优先级排序(Scrapy默认),由sorted set实现的一种非FIFO、LIFO方式。
SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderPriorityQueue'
# 可选的 按先进先出排序(FIFO)
# SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderQueue'
# 可选的 按后进先出排序(LIFO)
# SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.SpiderStack'
# 在redis中保持scrapy-redis用到的各个队列,从而允许暂停和暂停后恢复,也就是不清理redis queues
SCHEDULER_PERSIST = True
# 只在使用SpiderQueue或者SpiderStack是有效的参数,指定爬虫关闭的最大间隔时间
# SCHEDULER_IDLE_BEFORE_CLOSE = 10
# 通过配置RedisPipeline将item写入key为 spider.name : items 的redis的list中,供后面的分布式处理item
# 这个已经由 scrapy-redis 实现,不需要我们写代码
# ITEM_PIPELINES = {
#     #'distribute_country_tecah.pipelines.DistributeCountryPipeline':300,
#     'scrapy_redis.pipelines.RedisPipeline': 400
# }
# 指定redis数据库的连接参数
# REDIS_PASS是我自己加上的redis连接密码(默认不做)
REDIS_HOST = '10.0.30.2'
REDIS_PORT = 6379
REDIS_PARAMS ={
    'password': '123456',
    'db': 0
}
REDIS_ENCODING = 'utf-8'
# LOG等级
LOG_LEVEL = 'DEBUG'
#默认情况下,RFPDupeFilter只记录第一个重复请求。将DUPEFILTER_DEBUG设置为True会记录所有重复的请求。
DUPEFILTER_DEBUG =True
#REDIS_URL = 'redis://auth:123456@192.168.124.129:6379/db'

反反爬虫相关机制

通常防止爬虫被反主要有以下几个策略:

  • 动态设置User-Agent(随机切换User-Agent,模拟不同用户的浏览器信息)
  • 禁用Cookies(也就是不启用cookies middleware,不向Server发送cookies,有些网站通过cookie的使用发现爬虫行为)
    • 可以通过COOKIES_ENABLED 控制 CookiesMiddleware 开启或关闭
  • 设置延迟下载(防止访问过于频繁,设置为 2秒 或更高)
  • Google Cache 和 Baidu Cache:如果可能的话,使用谷歌/百度等搜索引擎服务器页面缓存获取页面数据。
  • 使用IP地址池:VPN和代理IP,现在大部分网站都是根据IP来ban的。
  • 使用Crawlera(专用于爬虫的代理组件),正确配置和设置下载中间件后,项目所有的request都是通过crawlera发出。
## 代理池设置
DOWNLOADER_MIDDLEWARES = {
    'scrapy_crawlera.CrawleraMiddleware': 600
}
CRAWLERA_ENABLED = True
CRAWLERA_USER = '注册/购买的UserKey'
CRAWLERA_PASS = '注册/购买的Password'

如何设置下载中间件

下载中间件是处于引擎(crawler.engine)和下载器(crawler.engine.download())之间的一层组件,可以有多个下载中间件被加载运行。

当引擎传递请求给下载器的过程中,下载中间件可以对请求进行处理 (例如增加http header信息,增加proxy信息等);

在下载器完成http请求,传递响应给引擎的过程中, 下载中间件可以对响应进行处理(例如进行gzip的解压等)

要激活下载器中间件组件,将其加入到 DOWNLOADER_MIDDLEWARES 设置中。 该设置是一个字典(dict),键为中间件类的路径,值为其中间件的顺序(order)。

这里是一个例子:

DOWNLOADER_MIDDLEWARES = {
    'mySpider.middlewares.MyDownloaderMiddleware': 543,
}

编写下载器中间件十分简单。每个中间件组件是一个定义了以下一个或多个方法的Python类:

class scrapy.contrib.downloadermiddleware.DownloaderMiddleware

process_request(self, request, spider)

  • 当每个request通过下载中间件时,该方法被调用。
  • process_request() 必须返回以下其中之一:一个 None 、一个 Response 对象、一个 Request 对象或 raise IgnoreRequest:
    • 如果其返回 None ,Scrapy将继续处理该request,执行其他的中间件的相应方法,直到合适的下载器处理函数(download handler)被调用, 该request被执行(其response被下载)。
    • 如果其返回 Response 对象,Scrapy将不会调用 任何 其他的 process_request() 或 process_exception() 方法,或相应地下载函数; 其将返回该response。 已安装的中间件的 process_response() 方法则会在每个response返回时被调用。
    • 如果其返回 Request 对象,Scrapy则停止调用 process_request方法并重新调度返回的request。当新返回的request被执行后, 相应地中间件链将会根据下载的response被调用。
    • 如果其raise一个 IgnoreRequest 异常,则安装的下载中间件的 process_exception() 方法会被调用。如果没有任何一个方法处理该异常, 则request的errback(Request.errback)方法会被调用。如果没有代码处理抛出的异常, 则该异常被忽略且不记录(不同于其他异常那样)。
  • 参数:
    • request (Request 对象) – 处理的request
    • spider (Spider 对象) – 该request对应的spider

process_response(self, request, response, spider)

当下载器完成http请求,传递响应给引擎的时候调用

  • process_request() 必须返回以下其中之一: 返回一个 Response 对象、 返回一个 Request -对象或raise一个 IgnoreRequest 异常。
    • 如果其返回一个 Response (可以与传入的response相同,也可以是全新的对象), 该response会被在链中的其他中间件的 process_response() 方法处理。
    • 如果其返回一个 Request 对象,则中间件链停止, 返回的request会被重新调度下载。处理类似于 process_request() 返回request所做的那样。
    • 如果其抛出一个 IgnoreRequest 异常,则调用request的errback(Request.errback)。 如果没有代码处理抛出的异常,则该异常被忽略且不记录(不同于其他异常那样)。
  • 参数:
    • request (Request 对象) – response所对应的request
    • response (Response 对象) – 被处理的response
    • spider (Spider 对象) – response所对应的spider

使用案例

  1. 创建middlewares.py文件。

Scrapy代理IP、Uesr-Agent的切换都是通过DOWNLOADER_MIDDLEWARES进行控制,我们在settings.py同级目录下创建middlewares.py文件,包装所有请求。

# middlewares.py
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import random
import base64
from settings import USER_AGENTS
from settings import PROXIES
# 随机的User-Agent
class RandomUserAgent(object):
    def process_request(self, request, spider):
        useragent = random.choice(USER_AGENTS)
        request.headers.setdefault("User-Agent", useragent)
class RandomProxy(object):
    def process_request(self, request, spider):
        proxy = random.choice(PROXIES)
        if proxy['user_passwd'] is None:
            # 没有代理账户验证的代理使用方式
            request.meta['proxy'] = "http://" + proxy['ip_port']
        else:
            # 对账户密码进行base64编码转换
            base64_userpasswd = base64.b64encode(proxy['user_passwd'])
            # 对应到代理服务器的信令格式里
            request.headers['Proxy-Authorization'] = 'Basic ' + base64_userpasswd
            request.meta['proxy'] = "http://" + proxy['ip_port']

为什么HTTP代理要使用base64编码:

HTTP代理的原理很简单,就是通过HTTP协议与代理服务器建立连接,协议信令中包含要连接到的远程主机的IP和端口号,如果有需要身份验证的话还需要加上授权信息,服务器收到信令后首先进行身份验证,通过后便与远程主机建立连接,连接成功之后会返回给客户端200,表示验证通过,就这么简单,下面是具体的信令格式:

CONNECT 59.64.128.198:21 HTTP/1.1
Host: 59.64.128.198:21
Proxy-Authorization: Basic bGV2I1TU5OTIz
User-Agent: OpenFetion

其中Proxy-Authorization是身份验证信息,Basic后面的字符串是用户名和密码组合后进行base64编码的结果,也就是对username:password进行base64编码。

HTTP/1.0 200 Connection established

OK,客户端收到收面的信令后表示成功建立连接,接下来要发送给远程主机的数据就可以发送给代理服务器了,代理服务器建立连接后会在根据IP地址和端口号对应的连接放入缓存,收到信令后再根据IP地址和端口号从缓存中找到对应的连接,将数据通过该连接转发出去。

  1. 修改settings.py配置USER_AGENTS和PROXIES
  • 添加USER_AGENTS
## 添加USER_AGENTS:
  USER_AGENTS = [
    "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Win64; x64; Trident/5.0; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 2.0.50727; Media Center PC 6.0)",
    "Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 6.0; Trident/4.0; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; .NET CLR 1.0.3705; .NET CLR 1.1.4322)",
    "Mozilla/4.0 (compatible; MSIE 7.0b; Windows NT 5.2; .NET CLR 1.1.4322; .NET CLR 2.0.50727; InfoPath.2; .NET CLR 3.0.04506.30)",
    "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN) AppleWebKit/523.15 (KHTML, like Gecko, Safari/419.3) Arora/0.3 (Change: 287 c9dfb30)",
    "Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/527+ (KHTML, like Gecko, Safari/419.3) Arora/0.6",
    "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2pre) Gecko/20070215 K-Ninja/2.1.1",
    "Mozilla/5.0 (Windows; U; Windows NT 5.1; zh-CN; rv:1.9) Gecko/20080705 Firefox/3.0 Kapiko/3.0",
    "Mozilla/5.0 (X11; Linux i686; U;) Gecko/20070322 Kazehakase/0.4.5"
    ]
  • 添加代理IP设置PROXIES:
## 添加代理IP设置PROXIES:
## 免费代理IP可以网上搜索,或者付费购买一批可用的私密代理IP:
PROXIES = [
    {'ip_port': '111.8.60.9:8123', 'user_passwd': 'user1:pass1'},
    {'ip_port': '101.71.27.120:80', 'user_passwd': 'user2:pass2'},
    {'ip_port': '122.96.59.104:80', 'user_passwd': 'user3:pass3'},
    {'ip_port': '122.224.249.122:8088', 'user_passwd': 'user4:pass4'},
]
  • 除非特殊需要,禁用cookies,防止某些网站根据Cookie来封锁爬虫。
COOKIES_ENABLED = False
  • 设置下载延迟
DOWNLOAD_DELAY = 3
  • 最后设置setting.py里的DOWNLOADER_MIDDLEWARES,添加自己编写的下载中间件类。
DOWNLOADER_MIDDLEWARES = {
    #'mySpider.middlewares.MyCustomDownloaderMiddleware': 543,
    'mySpider.middlewares.RandomUserAgent': 1,
    'mySpider.middlewares.ProxyMiddleware': 100
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

发呆的比目鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值