• 安装:
  • 基本使用
    1. scrapy startproject 工程名
      1. spiders :爬虫文件夹
        1. 必须存放一个爬虫源文件
      2. settings.py:工程的配置文件
        1. 更改 USER_AGENT
    2. cd 工程名
      1. 创建爬虫文件夹 : 可以创建多个
        1. scrapy genspider spiderNAME www.xxx.com
        2. 编写对应的代码 在爬虫文件中
          1. parse 函数
            1. scrapy xpath 返回的是一个 selector 对象 数据用 extract或者 extract_first解析
      2. 执行工程 :scrapy crawl spiderName
        1. 默认会输出所有的日志信息
          1. settings.py
            1. LOG_LEVEL = “ERROR” # 指定错误类型日志输出 减少cpu使用
            2. ROBOTSTXT_OBEY = False 禁止robots协议
            3. CONCURRENT_REQUESTS = 100 : 并发线程数
            4. 禁止cookie: COOKIES_ENABLED = False ;减少cpu使用
            5. 禁止重试: RETRY_ENABLED=False
              1. 禁止请求异常时中间件的修改操作
            6. 减少下载超时:
              1. DOWNLOAD_TIMEOUT =10 # 单位是秒
  1. 持久化存储:
    1. 1 基于终端指令的持久化存储
      1. 将 parse 的返回值保存的文件中
      2. scrapy crawl spiderName -o 文件
        1. 文件有格式要求
          1. csv 、json、jxml、marshal、。。。。
    2. 2 基于管道的持久化存储
      1. 在爬虫文件中进行数据解析
      2. 在items.py中定义相关属性
        1. 步骤一解析出几个属性,定义几个属性
          1. name = scrapy.Field()
      3. 在爬虫文件中将解析的数据存储封装到Item类型的对象中
      4. 将Item类型的对象提交给管道
        1. yield item
      5. 在管道文件(pipelines.py)中接受爬虫文件提交过来的item类型对象,且对其进行任意形式的持久化存储操作
        1. open_spider(self, spider):
          1. 爬行器被打开时,执行
        2. close_spider(self, spider):
          1. 爬行器被结束时,执行
      6. 在配置文件中开启管道机制
    3. 基于管道实现数据的备份
      1. 将爬取的数据分别存储到不同的载体
        1. 一份存入 mysql 一份存入 redis
        2. 新建一个管道类
        3. 在settings.py 的 ITEM_PIPELINES 加入
          1. 类的位置:优先级(数字)
        4. 优先级高的类 的 process_item(self, item, spider):要返回 item
          1. return 是将item 传递给下一个将要执行的管道类
  2. 请求传参

    1. 重写请求方法
      1. scrapy.Request(url=url, callback=self.parse) get请求
      2. scrapy.FormRequest(url=url, callback=self.parse) post请求
    2. 多页爬取

      1. class DomeSpider(scrapy.Spider):
      2. name = 'dome' # 爬虫文件的唯一标识
      3. # 运行的域名
      4. # allowed_domains = ['www.baidu.com']
      5. # 起始url列表:只可以储存url
      6. # 作用 列表中储存的url都会被进行get请求的发送
      7. start_urls = ['http://xxx/1.html']
      8. # 第一页
      9. page = 1
      10. # 数据解析
      11. # start_urls的url请求成功一次 parse就会调用一次
      12. # response 请求的结果
      13. def parse(self, response):
      14. title_content_list = response.xpath('//section//main/article')
      15. for title_content in title_content_list:
      16. # xpath 返回的是一个 selector 对象 数据用 extract或者 extract_first解析
      17. title = title_content.xpath('./div[1]/h1/a/text()').extract_first()
      18. content = title_content.xpath('./div[2]/p/text()').extract_first()
      19. item = Dome1SacrpyItem()
      20. item["title"] = title
      21. item["content"] = content
      22. yield item
      23. if self.page < 5:
      24. self.page += 1 # 页数叠加
      25. url = f"http://duanziwang.com/category/{self.page}/index.html"
      26. yield scrapy.Request(url=url, callback=self.parse)
    3. 深度爬取

      1. class DomeSpider(scrapy.Spider):
      2. name = 'dome' # 爬虫文件的唯一标识
      3. # 运行的域名
      4. # allowed_domains = ['www.baidu.com']
      5. # 起始url列表:只可以储存url
      6. # 作用 列表中储存的url都会被进行get请求的发送
      7. start_urls = ['http://duanziwang.com/category/经典段子/index.html']
      8. # 数据解析
      9. # start_urls的url请求成功一次 parse就会调用一次
      10. # response 请求的结果
      11. page = 1
      12. def parse(self, response):
      13. title_content_list = response.xpath('//section//main/article')
      14. for title_content in title_content_list:
      15. # xpath 返回的是一个 selector 对象 数据用 extract或者 extract_first解析
      16. # 商品
      17. title = title_content.xpath('./div[1]/h1/a/text()').extract_first()
      18. item = Dome1SacrpyItem()
      19. item["title"] = title
      20. # 商品详情页url
      21. new_url = title_content.xpath('./div[2]/p/text()').extract_first()
      22. # meta 就是 ==> 请求传参 --------------------------------------
      23. yield scrapy.Request(url=new_url, callback=self.parse_xqy, meta={"item": item})
      24. if self.page < 5:
      25. self.page += 1 # 页数叠加
      26. url = f"http://duanziwang.com/category/{self.page}/index.html"
      27. yield scrapy.FormRequest(url=url, callback=self.parse)
      28. # 详情页解析
      29. def parse_xqy(self, response):
      30. content = response.xpath('./div[2]/p/text()').extract_first()
      31. item = response.meta["item"]
      32. item["content"] = content
      33. yield item
  3. 中间件 <==>middlewares.py

    1. 爬虫中间件
    2. 下载中间件
      1. process_request(self, request, spider): 拦截请求
        1. 篡改请求UA
        2. 篡改url
        3. 篡改cookie
      2. process_response(self, request, response, spider): 拦截响应
        1. 篡改响应数据
      3. process_exception(self, request, exception, spider):拦截异常
        1. 修正错误url,重新发起请求
          1. 代理修改 proxy
          2. url 修改
  4. 大文件下载

    1. 图片、音频、视频 可以在管道类中进行请求
    2. 原始的管道类是没有这个条件的
    3. scrapy 有封装好的管道类

      1. from scrapy.pipelines.images import ImagesPipeline
      2. 在settings.py中设置图片存放的文件夹路径
        1. IMAGES_STORE = “./image/“
      3. 通过继承,在改写下面的三个方法,可以实现文件下载的功能
        1. item 中必须有 image_urls,images 两个参数 ```python class ImgPipeline(ImagesPipeline):

      请求图片数据

      def get_media_requests(self, item, info): yield scrapy.Request(url=item[“src”], meta={item: “item”})

      得到图片名称

      def file_path(self, request, response=None, info=None, *, item=None): item = request.meta[“item”] return item[“filename”]

      将item 给下一个管道类

      def item_completed(self, results, item, info): return item ```

CrawlSpider

  • 作用:全网页爬取
    • 爬取网页上符合规则的url,通过当前爬取下一页的url
    • 直到全部url获取到
  • 创建方式
    1. 1. scrapy startproject 工程名
    2. 1. cd 工程名
    3. 1. scrapy genspider -t crawl 爬虫文件 www.xxx.com
    4. 1. scrapy crawl 爬虫文件
  • 实例
    • xxx

分布式

  • 建立一个分布式机群,让机群中的每一台电脑执行同一程序,让其对同一组资源进行
    • 联合且分布的数据爬取
  • 通过scrapy-redis 组件
  • 使用
    • 建立工程
      • 。。。。。
    • ①:修改爬虫文件
      • from scrapy_redis.spiders import RedisCrawlSpider
      • 修改爬虫父类为 RedisCrawlSpider
      • 添加 redis_key 属性 : redis_key = “xxx”,注释调allowed_domains,start_urls两个属性
      • 正常解析
    • ②:对seetings.py进行配置 (配置文件中不要加 LOG_LEVEL)
      • 指定调度器
        • 使用scrapy-redis组件的去重队列

          • DUPEFILTER_CLASS = “scrapy_redis.dupefilter.RFPDupeFilter”
        • 使用scrapy-redis组件自己的调度器

          • SCHEDULER = “scrapy_redis.scheduler.Scheduler”
        • 核心配置# 是否允许暂停

          • SCHEDULER_PERSIST = True # 值为True表示:宕机恢复服务时,从宕机的那个地方开始爬取,不用从头开始
      • 使用scrapy-redis组件中封装好的可以被共享的管道。
        • ITEM_PIPELINES = { ‘scrapy_redis.pipelines.RedisPipeline’: 400, }
      •  管道默认会连接且将数据存储到本机的redis服务中,如果想要连接存储到其他redis服务中需要在settings.py中进行如下配置
        • 如果redis服务器不在自己本机,则需要做如下配置

          • REDIS_HOST = ‘192.168.31.31’ # redis服务的ip地址
          • REDIS_PORT = 6379
          • REDIS_ENCODING = ‘utf-8’ # 可选配置

          • REDIS_PARAMS = {‘password’:’123456’} # 可选配置

      • 修改ua和关闭robots协议
        • USER_AGENT = ‘XXXX’ # 伪装请求载体身份
        • ROBOTSTXT_OBEY = False # 不遵从门户网站robots协议,避免某些信息爬取不到
    • ③:redis数据库设置 :修改 redis.windows.conf
      • 56行:# bind 127.0.0.1
        • 不注释时,只允许本机的客户端连接

      • 75行: protected-mode no
        • yes改为no,关闭redis的保护模式,客户端可以对服务器进行读写操作

    • ④:启动redis服务器和客服端
      • redis-server 开启服务器
      • redis-cli 开启客户端
    • ⑤:执行工程
      • scrapy crawl 工程名
    • ⑥:向redis_kiy 中加入起始url
      • redis 客户端 :lpush xxx www.xxxx.com
  • 查看redis

    • key *
    • lrange xxx:items 0 -1

      增量式

  • 概念:检测网站数据更新情况,以便于爬取到最新更新的数据

  • 核心:去重
  • 方式: 记录表
  • 实现
    • redis 的 set

补充:

  1. 添加 cookie:
    1. 将settings.py 的 COOKIES_ENABLED 改为 True
      1. 在下载中间件(MfwDownloaderMiddleware)的 process_request 里面添加:
        1. request.cookies = { key:value}
    2. 将settings.py 的 COOKIES_ENABLED 改为 Flase
      1. 重构 Spider 的 start_requests 函数
        1. cookie = { key:value}
        2. headers = { “User-Agent”=””, “Referer”: “”,}
        3. def start_requests(self):
          yield
          scrapy.Request(url=self.start_url_custom, cookies=self.cookie, headers=self.headers, callback=self.parse, dont_filter=True)
  2. scrapy+selenium:

    1. 在爬虫类中实例化一个浏览器驱动对象

      1. def init(self):
        self.driver = self.googleinterface()
        super()._init
        ()
      2. def google_interface(self, proxies=None): options = Options()
        options.add_argument(“—headless”) # 添加无头浏览器** options.add_argument(“—disable-gpu”)
        options.add_argument(“disable-infobars”)
        # js注册 跳过浏览器检测
        if proxies:
        options.add_argument(f”—proxy-server={proxies}”) #添加代理** options.add_argument(“start-maximized”)
        options.add_experimental_option(“excludeSwitches”, [ “enable-automation”])
        options.add_experimental_option(“useAutomationExtension”, False)

      google_diver = WebDriver(“chromedriver.exe”, options=options)
      with open(“stealth.min.js”) as f:
      js = f.read()
      google_diver.execute_cdp_cmd(“Page.addScriptToEvaluateOnNewDocument”, {
      “source”: js
      })
      # 最大化
      google_diver.maximize_window
      ()
      return **google_diver

    2. 2在下载中间件的 process_response 函数中修改

      1. def process_response(self, request, response, spider):
        # Called with the response returned from the downloader.
        # Must either;
        # - return a Response object
        # - return a Request object
        # - or raise IgnoreRequest
        if “/i/“ in request.url:
        spider.driver.get(request.url)
        time.sleep(7)
        # 页面下拉的最下面

spider.driver.execute_script(“window.scrollTo(0,document.body.scrollHeight);”) ** time.sleep(2)
spider.driver.execute_script(“window.scrollTo(0,document.body.scrollHeight);”)
time.sleep(2)
spider.driver.execute_script(“window.scrollTo(0,document.body.scrollHeight);”)
time.sleep(2)
first_half = spider.driver.page_source
return HtmlResponse(url=request.url, body=first_half, encoding=”utf8”, request=request)
return
response

  1. 在 setting文件中 添加:
    1. DOWNLOADER_MIDDLEWARES = {
      ‘MFW.middlewares.MfwDownloaderMiddleware’:
      543,
      }