zoukankan      html  css  js  c++  java
  • scrapy(2)

    回顾

    scrapy框架

    • 五大组件+工作流程+常用命令

       
       
       
      x
       
       
       
       
      1
      【1】五大组件
      2
          1.1) 引擎(Engine)
      3
          1.2) 爬虫程序(Spider)
      4
          1.3) 调度器(Scheduler)
      5
          1.4) 下载器(Downloader)
      6
          1.5) 管道文件(Pipeline)
      7
          1.6) 下载器中间件(Downloader Middlewares)
      8
          1.7) 蜘蛛中间件(Spider Middlewares)
      9
          
      10
      【2】工作流程
      11
          2.1) Engine向Spider索要URL,交给Scheduler入队列
      12
          2.2) Scheduler处理后出队列,通过Downloader Middlewares交给Downloader去下载
      13
          2.3) Downloader得到响应后,通过Spider Middlewares交给Spider
      14
          2.4) Spider数据提取:
      15
             a) 数据交给Pipeline处理
      16
             b) 需要跟进URL,继续交给Scheduler入队列,依次循环
      17
          
      18
      【3】常用命令
      19
          3.1) scrapy startproject 项目名
      20
          3.2) scrapy genspider 爬虫名 域名
      21
          3.3) scrapy crawl 爬虫名
       
       

    完成scrapy项目完整流程

    • 完整流程

       
       
       
      x
       
       
       
       
      1
      【1】scrapy startproject Tencent
      2
      【2】cd Tencent
      3
      【3】scrapy genspider tencent tencent.com
      4
      【4】items.py(定义爬取数据结构)
      5
          import scrapy
      6
          class TencentItem(scrapy.Item):
      7
              name = scrapy.Field()
      8
              address = scrapy.Field()
      9
          
      10
      【5】tencent.py(写爬虫文件)
      11
          import scrapy
      12
          from ..items import TencentItem
      13
          class TencentSpider(scrapy.Spider):
      14
              name = 'tencent'
      15
              allowed_domains = ['tencent.com']
      16
              start_urls = ['']
      17
              def parse(self, response):
      18
                  item = TencentItem()
      19
                  item['name'] = xxxx
      20
                  yield item
      21
      22
      【6】pipelines.py(数据处理)
      23
          class TencentPipeline(object):
      24
              def process_item(self, item, spider):
      25
                  return item
      26
          
      27
      【7】settings.py(全局配置)
      28
          
      29
      【8】run.py 
      30
          from scrapy import cmdline
      31
          cmdline.execute('scrapy crawl tencent'.split())
       
       

    我们必须记住

    • 熟练记住

       
       
       
      xxxxxxxxxx
      23
       
       
       
       
      1
      【1】响应对象response属性及方法
      2
          1.1) response.text :获取响应内容 - 字符串
      3
          1.2) response.body :获取bytes数据类型
      4
          1.3) response.xpath('')
      5
          1.4) response.xpath('').extract() :提取文本内容,将列表中所有元素序列化为Unicode字符串
      6
          1.5) response.xpath('').extract_first() :序列化提取列表中第1个文本内容
      7
          1.6) response.xpath('').get()  提取列表中第1个文本内容(等同于extract_first())
      8
          
      9
      【2】settings.py中常用变量
      10
          2.1) 设置数据导出编码(主要针对于json文件)
      11
               FEED_EXPORT_ENCODING = 'utf-8'
      12
          2.2) 设置User-Agent
      13
               USER_AGENT = ''
      14
          2.3) 设置最大并发数(默认为16)
      15
               CONCURRENT_REQUESTS = 32
      16
          2.4) 下载延迟时间(每隔多长时间请求一个网页)
      17
               DOWNLOAD_DELAY = 0.5
      18
          2.5) 请求头
      19
               DEFAULT_REQUEST_HEADERS = {'Cookie' : 'xxx'}
      20
          2.6) 添加项目管道
      21
               ITEM_PIPELINES = {'目录名.pipelines.类名' : 优先级}
      22
          2.7) cookie(默认禁用,取消注释-True|False都为开启)
      23
               COOKIES_ENABLED = False
       
       

    爬虫项目启动方式

    • 启动方式

       
       
       
      xxxxxxxxxx
      9
       
       
       
       
      1
      【1】方式一:基于start_urls
      2
          1.1) 从爬虫文件(spider)的start_urls变量中遍历URL地址交给调度器入队列,
      3
          1.2) 把下载器返回的响应对象(response)交给爬虫文件的parse(self,response)函数处理
      4
      5
      【2】方式二
      6
          重写start_requests()方法,从此方法中获取URL,交给指定的callback解析函数处理
      7
          2.1) 去掉start_urls变量
      8
          2.2) def start_requests(self):
      9
                   # 生成要爬取的URL地址,利用scrapy.Request()方法交给调度器
       
       

    2.笔记

    瓜子二手车直卖网 - 二级页面

    • 目标说明

       
       
       
      xxxxxxxxxx
      9
       
       
       
       
      1
      【1】在抓取一级页面的代码基础上升级
      2
      【2】一级页面所抓取数据(和之前一样):
      3
          2.1) 汽车链接
      4
          2.2) 汽车名称
      5
          2.3) 汽车价格
      6
      【3】二级页面所抓取数据
      7
          3.1) 行驶里程: //ul[@class="assort clearfix"]/li[2]/span/text()
      8
          3.2) 排量:    //ul[@class="assort clearfix"]/li[3]/span/text()
      9
          3.3) 变速箱:  //ul[@class="assort clearfix"]/li[4]/span/text()
       
       

    在原有项目基础上实现

    • 步骤1 - items.py

       
       
       
      xxxxxxxxxx
      15
       
       
       
       
      1
      # 添加二级页面所需抓取的数据结构
      2
      3
      import scrapy
      4
      5
      class GuaziItem(scrapy.Item):
      6
          # define the fields for your item here like:
      7
          # 一级页面: 链接、名称、价格
      8
          url = scrapy.Field()
      9
          name = scrapy.Field()
      10
          price = scrapy.Field()
      11
          # 二级页面: 时间、里程、排量、变速箱
      12
          time = scrapy.Field()
      13
          km = scrapy.Field()
      14
          disp = scrapy.Field()
      15
          trans = scrapy.Field()
       
       
    • 步骤2 - car2.py

       
       
       
      xxxxxxxxxx
      43
       
       
       
       
      1
      """
      2
      重写start_requests()方法,效率极高
      3
      """
      4
      # -*- coding: utf-8 -*-
      5
      import scrapy
      6
      from ..items import CarItem
      7
      8
      class GuaziSpider(scrapy.Spider):
      9
          # 爬虫名
      10
          name = 'car2'
      11
          # 允许爬取的域名
      12
          allowed_domains = ['www.guazi.com']
      13
          # 1、去掉start_urls变量
      14
          # 2、重写 start_requests() 方法
      15
          def start_requests(self):
      16
              """生成所有要抓取的URL地址,一次性交给调度器入队列"""
      17
              for i in range(1,6):
      18
                  url = 'https://www.guazi.com/bj/buy/o{}/#bread'.format(i)
      19
                  # scrapy.Request(): 把请求交给调度器入队列
      20
                  yield scrapy.Request(url=url,callback=self.parse)
      21
      22
          def parse(self, response):
      23
              # 基准xpath: 匹配所有汽车的节点对象列表
      24
              li_list = response.xpath('//ul[@class="carlist clearfix js-top"]/li')
      25
              # 给items.py中的 GuaziItem类 实例化
      26
              item = CarItem()
      27
              for li in li_list:
      28
                  item['url'] = 'https://www.guazi.com' + li.xpath('./a[1]/@href').get()
      29
                  item['name'] = li.xpath('./a[1]/@title').get()
      30
                  item['price'] = li.xpath('.//div[@class="t-price"]/p/text()').get()
      31
                  # Request()中meta参数: 在不同解析函数之间传递数据,item数据会随着response一起返回
      32
                  yield scrapy.Request(url=item['url'], meta={'meta_1': item}, callback=self.detail_parse)
      33
      34
          def detail_parse(self, response):
      35
              """汽车详情页的解析函数"""
      36
              # 获取上个解析函数传递过来的 meta 数据
      37
              item = response.meta['meta_1']
      38
              item['km'] = response.xpath('//ul[@class="assort clearfix"]/li[2]/span/text()').get()
      39
              item['disp'] = response.xpath('//ul[@class="assort clearfix"]/li[3]/span/text()').get()
      40
              item['trans'] = response.xpath('//ul[@class="assort clearfix"]/li[4]/span/text()').get()
      41
      42
              # 1条数据最终提取全部完成,交给管道文件处理
      43
              yield item
       
       
    • 步骤3 - pipelines.py

       
       
       
      x
       
       
       
       
      1
      # 将数据存入mongodb数据库,此处我们就不对MySQL表字段进行操作了,如有兴趣可自行完善
      2
      # MongoDB管道
      3
      import pymongo
      4
      5
      class GuaziMongoPipeline(object):
      6
          def open_spider(self, spider):
      7
              """爬虫项目启动时只执行1次,用于连接MongoDB数据库"""
      8
              self.conn = pymongo.MongoClient(MONGO_HOST,MONGO_PORT)
      9
              self.db = self.conn[MONGO_DB]
      10
              self.myset = self.db[MONGO_SET]
      11
      12
          def process_item(self,item,spider):
      13
              car_dict = dict(item)
      14
              self.myset.insert_one(car_dict)
      15
              
      16
              return item
       
       
    • 步骤4 - settings.py

       
       
       
      xxxxxxxxxx
      5
       
       
       
       
      1
      # 定义MongoDB相关变量
      2
      MONGO_HOST = 'localhost'
      3
      MONGO_PORT = 27017
      4
      MONGO_DB = 'guazidb'
      5
      MONGO_SET = 'guaziset'
       
       

    盗墓笔记小说抓取 - 三级页面

    • 目标

       
       
       
      xxxxxxxxxx
      4
       
       
       
       
      1
      【1】URL地址 :http://www.daomubiji.com/
      2
      【2】要求 : 抓取目标网站中盗墓笔记所有章节的所有小说的具体内容,保存到本地文件
      3
          ./data/novel/盗墓笔记1:七星鲁王宫/七星鲁王_第一章_血尸.txt
      4
          ./data/novel/盗墓笔记1:七星鲁王宫/七星鲁王_第二章_五十年后.txt
       
       
    • 准备工作xpath

       
       
       
      xxxxxxxxxx
      13
       
       
       
       
      1
      【1】一级页面 - 大章节标题、链接:
      2
          1.1) 基准xpath匹配a节点对象列表:  '//li[contains(@id,"menu-item-20")]/a'
      3
          1.2) 大章节标题: './text()'
      4
          1.3) 大章节链接: './@href'
      5
          
      6
      【2】二级页面 - 小章节标题、链接
      7
          2.1) 基准xpath匹配article节点对象列表: '//article'
      8
          2.2) 小章节标题: './a/text()'
      9
          2.3) 小章节链接: './a/@href'
      10
          
      11
      【3】三级页面 - 小说内容
      12
          3.1) p节点列表: '//article[@class="article-content"]/p/text()'
      13
          3.2) 利用join()进行拼接: ' '.join(['p1','p2','p3',''])
       
       

    项目实现

    • 1、创建项目及爬虫文件

       
       
       
      xxxxxxxxxx
      3
       
       
       
       
      1
      scrapy startproject Daomu
      2
      cd Daomu
      3
      scrapy genspider daomu www.daomubiji.com
       
       
    • 2、定义要爬取的数据结构 - itemspy

       
       
       
      xxxxxxxxxx
      6
       
       
       
       
      1
      class DaomuItem(scrapy.Item):
      2
          # 拷问: 你的pipelines.py中需要处理哪些数据? 文件名、路径
      3
          # 文件名:小标题名称  son_title: 七星鲁王 第一章 血尸
      4
          son_title = scrapy.Field()
      5
          directory = scrapy.Field()
      6
          content = scrapy.Field()
       
       
    • 3、爬虫文件实现数据抓取 - daomu.py

       
       
       
      xxxxxxxxxx
      51
       
       
       
       
      1
      # -*- coding: utf-8 -*-
      2
      import scrapy
      3
      from ..items import DaomuItem
      4
      import os
      5
      6
      class DaomuSpider(scrapy.Spider):
      7
          name = 'daomu'
      8
          allowed_domains = ['www.daomubiji.com']
      9
          start_urls = ['http://www.daomubiji.com/']
      10
      11
          def parse(self, response):
      12
              """一级页面解析函数:提取大标题+大链接,并把大链接交给调度器入队列"""
      13
              a_list = response.xpath('//li[contains(@id,"menu-item-20")]/a')
      14
              for a in a_list:
      15
                  item = DaomuItem()
      16
                  parent_title = a.xpath('./text()').get()
      17
                  parent_url = a.xpath('./@href').get()
      18
                  item['directory'] = './novel/{}/'.format(parent_title)
      19
                  # 创建对应文件夹
      20
                  if not os.path.exists(item['directory']):
      21
                      os.makedirs(item['directory'])
      22
                  # 交给调度器入队列
      23
                  yield scrapy.Request(url=parent_url, meta={'meta_1':item}, callback=self.detail_page)
      24
      25
          # 返回了11个response,调用了这个函数
      26
          def detail_page(self, response):
      27
              """二级页面解析函数:提取小标题、小链接"""
      28
              # 把item接收
      29
              meta_1 = response.meta['meta_1']
      30
              art_list = response.xpath('//article')
      31
              for art in art_list:
      32
                  # 只要有继续交往调度器的请求,就必须新建item对象
      33
                  item = DaomuItem()
      34
                  item['son_title'] = art.xpath('./a/text()').get()
      35
                  son_url = art.xpath('./a/@href').get()
      36
                  item['directory'] = meta_1['directory']
      37
                  # 再次交给调度器入队列
      38
                  yield scrapy.Request(url=son_url, meta={'item':item}, callback=self.get_content)
      39
      40
          # 盗墓笔记1: 传过来了75个response
      41
          # 盗墓笔记2: 传过来了 n 个response
      42
          # ... ...
      43
          def get_content(self, response):
      44
              """三级页面解析函数:提取具体小说内容"""
      45
              item = response.meta['item']
      46
              # content_list: ['段落1','段落2','段落3',...]
      47
              content_list = response.xpath('//article[@class="article-content"]/p/text()').extract()
      48
              item['content'] = '
      '.join(content_list)
      49
      50
              # 至此,一条item数据全部提取完成
      51
              yield item
       
       
    • 4、管道文件实现数据处理 - pipelines.py

       
       
       
      xxxxxxxxxx
      8
       
       
       
       
      1
      class DaomuPipeline(object):
      2
          def process_item(self, item, spider):
      3
              # filename: ./novel/盗墓笔记1:七星鲁王宫/七星鲁王_第一章_血尸.txt
      4
              filename = '{}{}.txt'.format(item['directory'], item['son_title'].replace(' ', '_'))
      5
              with open(filename, 'w') as f:
      6
                  f.write(item['content'])
      7
      8
              return item
       
       
    • 5、全局配置 - setting.py

       
       
       
      xxxxxxxxxx
      10
       
       
       
       
      1
      ROBOTSTXT_OBEY = False
      2
      DOWNLOAD_DELAY = 0.5
      3
      DEFAULT_REQUEST_HEADERS = {
      4
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
      5
        'Accept-Language': 'en',
      6
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36'
      7
      }
      8
      ITEM_PIPELINES = {
      9
         'Daomu.pipelines.DaomuPipeline': 300,
      10
      }
       
       

    Scrapy数据持久化

    • 数据持久化 - 数据库

       
       
       
      xxxxxxxxxx
      15
       
       
       
       
      1
      【1】在setting.py中定义相关变量
      2
      【2】pipelines.py中导入settings模块
      3
      def open_spider(self,spider):
      4
      """爬虫开始执行1次,用于数据库连接"""
      5
              
      6
          def process_item(self,item,spider):
      7
              """具体处理数据"""
      8
              return item 
      9
          
      10
      def close_spider(self,spider):
      11
      """爬虫结束时执行1次,用于断开数据库连接"""   
      12
      【3】settings.py中添加此管道
      13
      ITEM_PIPELINES = {'':200}
      14
      15
      【注意】 :process_item() 函数中一定要 return item ,当前管道的process_item()的返回值会作为下一个管道 process_item()的参数
       
       
    • 数据持久化 - csv、json文件

       
       
       
      xxxxxxxxxx
      8
       
       
       
       
      1
      【1】存入csv文件
      2
          scrapy crawl car -o car.csv
      3
      
      
      4
      【2】存入json文件
      5
          scrapy crawl car -o car.json
      6
      7
      【3】注意: settings.py中设置导出编码 - 主要针对json文件
      8
          FEED_EXPORT_ENCODING = 'utf-8'
       
       

    腾讯招聘职位数据持久化

    • scrapy项目代码

       
       
       
      xxxxxxxxxx
      1
       
       
       
       
      1
      见day07笔记:Tencent 文件夹
       
       
    • 建库建表SQL

       
       
       
      xxxxxxxxxx
      10
       
       
       
       
      1
      create database tencentdb charset utf8;
      2
      use tencentdb;
      3
      create table tencenttab(
      4
      job_name varchar(200),
      5
      job_type varchar(200),
      6
      job_duty varchar(2000),
      7
      job_require varchar(2000),
      8
      job_add varchar(100),
      9
      job_time varchar(100)
      10
      )charset=utf8;
       
       
    • MySQL数据持久化实现

       
       
       
      xxxxxxxxxx
      38
       
       
       
       
      1
      # 【1】settings.py添加
      2
      ITEM_PIPELINES = {
      3
         # 在原来基础上添加MySQL的管道
      4
         'Tencent.pipelines.TencentMysqlPipeline': 200,
      5
      }
      6
      MYSQL_HOST = '127.0.0.1'
      7
      MYSQL_USER = 'root'
      8
      MYSQL_PWD = '123456'
      9
      MYSQL_DB = 'tencentdb'
      10
      CHARSET = 'utf8'
      11
      12
      # 【2】pipelines.py新建MySQL管道类
      13
      from .settings import *
      14
      import pymysql
      15
      16
      class TencentMysqlPipeline:
      17
          def open_spider(self, spider):
      18
              self.db = pymysql.connect(MYSQL_HOST, MYSQL_USER, MYSQL_PWD, MYSQL_DB, charset=CHARSET)
      19
              self.cur = self.db.cursor()
      20
              self.ins = 'insert into tencenttab values(%s,%s,%s,%s,%s,%s)'
      21
      22
          def process_item(self, item, spider):
      23
              li = [
      24
                  item['job_name'],
      25
                  item['job_type'],
      26
                  item['job_duty'],
      27
                  item['job_require'],
      28
                  item['job_add'],
      29
                  item['job_time'],
      30
              ]
      31
              self.cur.execute(self.ins, li)
      32
              self.db.commit()
      33
      34
              return item
      35
      36
          def close_spider(self, item, spider):
      37
              self.cur.close()
      38
              self.db.close()
       
       
    • MongoDB数据持久化实现

       
       
       
      xxxxxxxxxx
      22
       
       
       
       
      1
      # 【1】settings.py中添加
      2
      ITEM_PIPELINES = {
      3
         # 添加MongoDB管道
      4
         'Tencent.pipelines.TencentMongoPipeline': 400,
      5
      }
      6
      MONGO_HOST = '127.0.0.1'
      7
      MONGO_PORT = 27017
      8
      MONGO_DB = 'tencentdb'
      9
      MONGO_SET = 'tencentset'
      10
      11
      # 【2】pipelines.py中新建MongoDB管道类
      12
      from .settings import *
      13
      import pymongo
      14
      15
      class TencentMongoPipeline:
      16
          def open_spider(self, spider):
      17
              self.conn = pymongo.MongoClient(MONGO_HOST, MONGO_PORT)
      18
              self.db = self.conn[MONGO_DB]
      19
              self.myset = self.db[MONGO_SET]
      20
      21
          def process_item(self, item, spider):
      22
              self.myset.insert_one(dict(item))
       
       
    • csv及json数据持久化实现

       
       
       
      xxxxxxxxxx
      6
       
       
       
       
      1
      【1】csv
      2
          scrapy crawl tencent -o tencent.csv
      3
          
      4
      【2】json
      5
          settings.py中添加变量: FEED_EXPORT_ENCODING = 'utf-8'
      6
          scrapy crawl tencent -o tencent.json
       
       

    分布式爬虫

    • 分布式爬虫介绍

       
       
       
      xxxxxxxxxx
      6
       
       
       
       
      1
      【1】原理
      2
          多台主机共享1个爬取队列
      3
          
      4
      【2】实现
      5
          2.1) 重写scrapy调度器(scrapy_redis模块)
      6
          2.2) sudo pip3 install scrapy_redis
       
       
    • 为什么使用redis

       
       
       
      xxxxxxxxxx
      2
       
       
       
       
      1
      【1】Redis基于内存,速度快
      2
      【2】Redis非关系型数据库,Redis中集合,存储每个request的指纹
       
       

    scrapy_redis详解

    • GitHub地址

       
       
       
      xxxxxxxxxx
      1
       
       
       
       
      1
      https://github.com/rmax/scrapy-redis
       
       
    • settings.py说明

       
       
       
      xxxxxxxxxx
      25
       
       
       
       
      1
      # 重新指定调度器: 启用Redis调度存储请求队列
      2
      SCHEDULER = "scrapy_redis.scheduler.Scheduler"
      3
      4
      # 重新指定去重机制: 确保所有的爬虫通过Redis去重
      5
      DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
      6
      7
      # 不清除Redis队列: 暂停/恢复/断点续爬(默认清除为False,设置为True不清除)
      8
      SCHEDULER_PERSIST = True
      9
      10
      # 优先级队列 (默认)
      11
      SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.PriorityQueue'
      12
      #可选用的其它队列
      13
      # 先进先出
      14
      SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.FifoQueue'
      15
      # 后进先出
      16
      SCHEDULER_QUEUE_CLASS = 'scrapy_redis.queue.LifoQueue'
      17
      18
      # redis管道
      19
      ITEM_PIPELINES = {
      20
          'scrapy_redis.pipelines.RedisPipeline': 300
      21
      }
      22
      23
      #指定连接到redis时使用的端口和地址
      24
      REDIS_HOST = 'localhost'
      25
      REDIS_PORT = 6379
       
       

    腾讯招聘分布式改写

    • 分布式爬虫完成步骤

       
       
       
      xxxxxxxxxx
      2
       
       
       
       
      1
      【1】首先完成非分布式scrapy爬虫 : 正常scrapy爬虫项目抓取
      2
      【2】设置,部署成为分布式爬虫
       
       
    • 分布式环境说明

       
       
       
      xxxxxxxxxx
      4
       
       
       
       
      1
      【1】分布式爬虫服务器数量: 2(其中1台Windows,1台Ubuntu虚拟机)
      2
      【2】服务器分工:
      3
          2.1) Windows : 负责数据抓取
      4
          2.2) Ubuntu  : 负责URL地址统一管理,同时负责数据抓取
       
       
    • 腾讯招聘分布式爬虫 - 数据同时存入1个Redis数据库

       
       
       
      xxxxxxxxxx
      22
       
       
       
       
      1
      【1】完成正常scrapy项目数据抓取(非分布式 - 拷贝之前的Tencent)
      2
      3
      【2】设置settings.py,完成分布式设置
      4
          2.1-必须) 使用scrapy_redis的调度器
      5
               SCHEDULER = "scrapy_redis.scheduler.Scheduler"
      6
              
      7
          2.2-必须) 使用scrapy_redis的去重机制
      8
               DUPEFILTER_CLASS = "scrapy_redis.dupefilter.RFPDupeFilter"
      9
              
      10
          2.3-必须) 定义redis主机地址和端口号
      11
               REDIS_HOST = '192.168.1.107'
      12
               REDIS_PORT = 6379
      13
              
      14
          2.4-非必须) 是否清除请求指纹,True:不清除 False:清除(默认)
      15
               SCHEDULER_PERSIST = True
      16
              
      17
          2.5-非必须) 在ITEM_PIPELINES中添加redis管道,数据将会存入redis数据库
      18
               'scrapy_redis.pipelines.RedisPipeline': 200
      19
                  
      20
      【3】把代码原封不动的拷贝到分布式中的其他爬虫服务器,同时开始运行爬虫
      21
      22
      【结果】:多台机器同时抓取,数据会统一存到Ubuntu的redis中,而且所抓数据不重复
       
       
    • 腾讯招聘分布式爬虫 - 数据存入MySQL数据库

       
       
       
      xxxxxxxxxx
      27
       
       
       
       
      1
      """和数据存入redis步骤基本一样,只是变更一下管道和MySQL数据库服务器的IP地址"""
      2
      【1】settings.py
      3
          1.1) SCHEDULER = 'scrapy_redis.scheduler.Scheduler'
      4
          1.2) DUPEFILTER_CLASS = 'scrapy_redis.dupefilter.RFPDupeFilter'
      5
          1.3) SCHEDULER_PERSIST = True
      6
          1.4) REDIS_HOST = '192.168.1.105'
      7
          1.5) REDIS_PORT = 6379
      8
          1.6) ITEM_PIPELINES = {'Tencent.pipelines.TencentMysqlPipeline' : 300}
      9
          1.7) MYSQL_HOST = '192.168.1.105'
      10
          
      11
      【2】将代码拷贝到分布式中所有爬虫服务器
      12
      13
      【3】多台爬虫服务器同时运行scrapy爬虫
      14
      15
      # 赠送腾讯MySQL数据库建库建表语句
      16
      """
      17
      create database tencentdb charset utf8;
      18
      use tencentdb;
      19
      create table tencenttab(
      20
      job_name varchar(1000),
      21
      job_type varchar(200),
      22
      job_duty varchar(5000),
      23
      job_require varchar(5000),
      24
      job_address varchar(200),
      25
      job_time varchar(200)
      26
      )charset=utf8;
      27
      """
       
       

    机器视觉与tesseract

    • 概述

       
       
       
      xxxxxxxxxx
      12
       
       
      1
      【1】作用
      2
          处理图形验证码
      3
      4
      【2】三个重要概念 - OCR、tesseract-ocr、pytesseract
      5
          2.1) OCR
      6
              光学字符识别(Optical Character Recognition),通过扫描等光学输入方式将各种票据、报刊、书籍、文稿及其它印刷品的文字转化为图像信息,再利用文字识别技术将图像信息转化为电子文本
      7
      8
          2.2) tesseract-ocr
       
       
      9
              OCR的一个底层识别库(不是模块,不能导入),由Google维护的开源OCR识别库
      10
      11
          2.3) pytesseract
      12
              Python模块,可调用底层识别库,是对tesseract-ocr做的一层Python API封装
       
       
    • 安装tesseract-ocr

       
       
       
      xxxxxxxxxx
      9
       
       
       
       
      1
      【1】Ubuntu安装
      2
          sudo apt-get install tesseract-ocr
      3
      4
      【2】Windows安装
      5
          2.1) 下载安装包
      6
          2.2) 添加到环境变量(Path)
      7
      8
      【3】测试(终端 | cmd命令行)
      9
          tesseract xxx.jpg 文件名
       
       
    • 安装pytesseract

       
       
       
      xxxxxxxxxx
      13
       
       
       
       
      1
      【1】安装
      2
          sudo pip3 install pytesseract
      3
          
      4
      【2】使用示例
      5
          import pytesseract
      6
          # Python图片处理库
      7
          from PIL import Image
      8
      9
          # 创建图片对象
      10
          img = Image.open('test1.jpg')
      11
          # 图片转字符串
      12
          result = pytesseract.image_to_string(img)
      13
          print(result)
       
       

    补充 - 滑块缺口验证码案例

    豆瓣网登录

    • 案例说明

       
       
       
      xxxxxxxxxx
      6
       
       
       
       
      1
      【1】URL地址: https://www.douban.com/
      2
      【2】先输入几次错误的密码,让登录出现滑块缺口验证,以便于我们破解
      3
      【3】模拟人的行为
      4
          3.1) 先快速滑动
      5
          3.2) 到离重点位置不远的地方开始减速
      6
      【4】详细看代码注释
       
       
    • 代码实现

       
       
       
      xxxxxxxxxx
      83
       
       
       
       
      1
      """
      2
      说明:先输入几次错误的密码,出现滑块缺口验证码
      3
      """
      4
      from selenium import webdriver
      5
      # 导入鼠标事件类
      6
      from selenium.webdriver import ActionChains
      7
      import time
      8
      9
      # 加速度函数
      10
      def get_tracks(distance):
      11
          """
      12
          拿到移动轨迹,模仿人的滑动行为,先匀加速后匀减速
      13
          匀变速运动基本公式:
      14
          ①v=v0+at
      15
          ②s=v0t+½at²
      16
          """
      17
          # 初速度
      18
          v = 0
      19
          # 单位时间为0.3s来统计轨迹,轨迹即0.3内的位移
      20
          t = 0.3
      21
          # 位置/轨迹列表,列表内的一个元素代表0.3s的位移
      22
          tracks = []
      23
          # 当前的位移
      24
          current = 0
      25
          # 到达mid值开始减速
      26
          mid = distance*4/5
      27
          while current < distance:
      28
              if current < mid:
      29
                  # 加速度越小,单位时间内的位移越小,模拟的轨迹就越多越详细
      30
                  a = 2
      31
              else:
      32
                  a = -3
      33
      34
              # 初速度
      35
              v0 = v
      36
              # 0.3秒内的位移
      37
              s = v0*t+0.5*a*(t**2)
      38
              # 当前的位置
      39
              current += s
      40
              # 添加到轨迹列表
      41
              tracks.append(round(s))
      42
              # 速度已经达到v,该速度作为下次的初速度
      43
              v = v0 + a*t
      44
          return tracks
      45
          # tracks: [第一个0.3秒的移动距离,第二个0.3秒的移动距离,...]
      46
      47
      48
      # 1、打开豆瓣官网 - 并将窗口最大化
      49
      browser = webdriver.Chrome()
      50
      browser.maximize_window()
      51
      browser.get('https://www.douban.com/')
      52
      53
      # 2、切换到iframe子页面
      54
      login_frame = browser.find_element_by_xpath('//*[@id="anony-reg-new"]/div/div[1]/iframe')
      55
      browser.switch_to.frame(login_frame)
      56
      57
      # 3、密码登录 + 用户名 + 密码 + 登录豆瓣
      58
      browser.find_element_by_xpath('/html/body/div[1]/div[1]/ul[1]/li[2]').click()
      59
      browser.find_element_by_xpath('//*[@id="username"]').send_keys('15110225726')
      60
      browser.find_element_by_xpath('//*[@id="password"]').send_keys('zhanshen001')
      61
      browser.find_element_by_xpath('/html/body/div[1]/div[2]/div[1]/div[5]/a').click()
      62
      time.sleep(4)
      63
      64
      # 4、切换到新的iframe子页面 - 滑块验证
      65
      auth_frame = browser.find_element_by_xpath('//*[@id="TCaptcha"]/iframe')
      66
      browser.switch_to.frame(auth_frame)
      67
      68
      # 5、按住开始滑动位置按钮 - 先移动180个像素
      69
      element = browser.find_element_by_xpath('//*[@id="tcaptcha_drag_button"]')
      70
      # click_and_hold(): 按住某个节点并保持
      71
      ActionChains(browser).click_and_hold(on_element=element).perform()
      72
      # move_to_element_with_offset(): 移动到距离某个元素(左上角坐标)多少距离的位置
      73
      ActionChains(browser).move_to_element_with_offset(to_element=element,xoffset=180,yoffset=0).perform()
      74
      75
      # 6、使用加速度函数移动剩下的距离
      76
      tracks = get_tracks(28)
      77
      for track in tracks:
      78
          # move_by_offset() : 鼠标从当前位置移动到某个坐标
      79
          ActionChains(browser).move_by_offset(xoffset=track,yoffset=0).perform()
      80
      81
      # 7、延迟释放鼠标: release()
      82
      time.sleep(0.5)
      83
      ActionChains(browser).release().perform()
       
       

    Fiddler抓包工具

    • 配置Fiddler

       
       
       
      xxxxxxxxxx
      9
       
       
       
       
      1
      【1】Tools -> Options -> HTTPS
      2
          1.1) 添加证书信任:  勾选 Decrypt Https Traffic 后弹出窗口,一路确认
      3
          1.2) 设置之抓浏览器的包:  ...from browsers only
      4
      5
      【2】Tools -> Options -> Connections
      6
          2.1) 设置监听端口(默认为8888)
      7
      8
      【3】配置完成后重启Fiddler('重要'
      9
          3.1) 关闭Fiddler,再打开Fiddler
       
       
    • 配置浏览器代理

       
       
       
      xxxxxxxxxx
      10
       
       
       
       
      1
      【1】安装Proxy SwitchyOmega谷歌浏览器插件
      2
      3
      【2】配置代理
      4
          2.1) 点击浏览器右上角插件SwitchyOmega -> 选项 -> 新建情景模式 -> myproxy(名字) -> 创建
      5
          2.2) 输入  HTTP://  127.0.0.1  8888
      6
          2.3) 点击 :应用选项
      7
          
      8
      【3】点击右上角SwitchyOmega可切换代理
      9
      10
      【注意】: 一旦切换了自己创建的代理,则必须要打开Fiddler才可以上网
       
       
    • Fiddler常用菜单

       
       
       
      xxxxxxxxxx
      8
       
       
       
       
      1
      【1】Inspector :查看数据包详细内容
      2
          1.1) 整体分为请求和响应两部分
      3
          
      4
      【2】Inspector常用菜单
      5
          2.1) Headers :请求头信息
      6
          2.2) WebForms: POST请求Form表单数据 <body>
      7
                         GET请求查询参数: <QueryString>
      8
          2.3) Raw : 将整个请求显示为纯文本
       
       

    移动端app数据抓取

    • 方法1 - 手机 + Fiddler

       
       
       
      xxxxxxxxxx
      1
       
       
       
       
      1
      设置方法见文件夹 - 移动端抓包配置
       
       
    • 方法2 - F12浏览器工具

    有道翻译手机版破解案例

     
     
     
    xxxxxxxxxx
    17
     
     
     
     
    1
    import requests
    2
    from lxml import etree
    3
    4
    word = input('请输入要翻译的单词:')
    5
    6
    post_url = 'http://m.youdao.com/translate'
    7
    post_data = {
    8
      'inputtext':word,
    9
      'type':'AUTO'
    10
    }
    11
    12
    html = requests.post(url=post_url,data=post_data).text
    13
    parse_html = etree.HTML(html)
    14
    xpath_bds = '//ul[@id="translateResult"]/li/text()'
    15
    result = parse_html.xpath(xpath_bds)[0]
    16
    17
    print(result)
     
     
  • 相关阅读:
    http://www.cnblogs.com/fengyin/archive/2011/01/18/1938628.html 前端优化
    iframe中子父窗口互调的js方法
    Mydomain操作说明
    Struts中出现DispatchMapping[***] does not define a handler property 的解决办法
    MyEclipse 不编译了,无论怎么更改保存, classes目录下都是空的.
    checkstyle配置文件说明
    SQLite学习手册(数据类型)
    动态加载datagrid控件的一个问题
    sharepoint
    VS.net 的一个bug
  • 原文地址:https://www.cnblogs.com/yongqi-wang/p/13667916.html
Copyright © 2011-2022 走看看