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'] = '\n'.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)
 
 

 

 

 

 

 

 

 

posted @ 2020-09-14 17:24  爱吃萝卜爱吃兔  阅读(139)  评论(0编辑  收藏  举报