• scrapy爬虫框架


    scrapy框架是异步处理框架,可配置和可扩展程度非常高,Python中使用最广泛的爬虫框架。

    安装

    Ubuntu安装

    1、安装依赖包

    1. sudo apt-get install libffi-dev
    2. sudo apt-get install libssl-dev
    3. sudo apt-get install libxml2-dev
    4. sudo apt-get install python3-dev
    5. sudo apt-get install libxslt1-dev
    6. sudo apt-get install zlib1g-dev
    7. sudo pip3 install -I -U service_identity

    2、安装scrapy框架

    1. sudo pip3 install Scrapy

    Windows安装

      cmd命令行(管理员): python -m pip install Scrapy

    Scrapy框架五大组件

    1. 引擎(Engine)      :整个框架核心
    2. 调度器(Scheduler)   :维护请求队列
    3. 下载器(Downloader)  :获取响应对象,下载器是基于多线程的
    4. 爬虫文件(Spider)   :数据解析提取
    5. 项目管道(Pipeline)  :数据入库处理

    下载器中间件(Downloader Middlewares) : 引擎->下载器,包装请求(随机代理等)

    蜘蛛中间件(Spider Middlewares) : 引擎->爬虫文件,可修改响应对象属性

    scrapy爬虫工作流程

    爬虫项目启动

    1、由引擎向爬虫程序索要第一个要爬取的URL,交给调度器去入队列

    2、调度器处理请求后出队列,通过下载器中间件交给下载器去下载

    3、下载器得到响应对象后,通过蜘蛛中间件交给爬虫程序

    4、爬虫程序进行数据提取:

      1、数据交给管道文件去入库处理

      2、对于需要继续跟进的URL,再次交给调度器入队列,依次循环

    scrapy常用命令

    1、创建爬虫项目  scrapy startproject 项目名

    2、创建爬虫文件  scrapy genspider 爬虫名 域名

              域名为协议后面的名字

    3、运行爬虫    scrapy crawl 爬虫名

    在cmd窗口运行上面指令后,会在当前文件夹自动创建如下目录结构。

    scrapy项目目录结构

    Baidu                   # 项目文件夹
    ├── Baidu               # 项目目录
    │   ├── items.py        # 定义数据结构
    │   ├── middlewares.py    # 中间件
    │   ├── pipelines.py     # 数据处理
    │   ├── settings.py      # 全局配置
    │   └── spiders
    │       ├── baidu.py    # 爬虫文件
    └── scrapy.cfg           # 项目基本配置文件

    全局配置文件settings.py详解

    1、定义User-Agent

      USER_AGENT = 'Mozilla/5.0'

    2、是否遵循robots协议,一定要设置为False

      ROBOTSTXT_OBEY = False

    3、最大并发量,默认为16

      CONCURRENT_REQUESTS = 32

    4、下载延迟时间

      DOWNLOAD_DELAY = 1

    5、请求头,此处也可以添加User-Agent

      DEFAULT_REQUEST_HEADERS={}

    6、项目管道,运行管道函数

      ITEM_PIPELINES={

      '项目目录名.pipelines.类名':300

      }

    创建爬虫项目步骤

    1. 新建项目 :scrapy startproject 项目名
    2. cd 项目文件夹
    3. 新建爬虫文件 :scrapy genspider 文件名 域名
    4. 明确目标(items.py)
    5. 写爬虫程序(文件名.py)
    6. 管道文件(pipelines.py)
    7. 全局配置(settings.py)
    8. 运行爬虫 :scrapy crawl 爬虫名

    pycharm运行爬虫项目

    1、创建一个脚本文件,比如:begin.py(和scrapy.cfg文件同目录)

    2、begin.py中内容:

    from scrapy import cmdline
    cmdline.execute('scrapy crawl maoyan'.split())

    导入cmd命令行模块,在python中写cmd命令,之所以用split()是因为把字符串按空格切割,这样cmd才能识别是3个参数。

    百度

    目标:打开百度首页,把 '百度一下,你就知道' 抓取下来,从终端输出

    实现步骤

    1、创建项目Baidu 和 爬虫文件baidu

    1、scrapy startproject Baidu
    2、cd Baidu
    3、scrapy genspider baidu www.baidu.com

    2、编写爬虫文件baidu.py,xpath提取数据

    # -*- coding: utf-8 -*-
    import scrapy
    
    
    class BaiduSpider(scrapy.Spider):
        name = 'baidu'      # 爬虫名 : scrapy crawl 爬虫名
        allowed_domains = ['www.baidu.com']     # 允许爬取的域名
        start_urls = ['http://www.baidu.com/']      # 起始URL地址
    
        def parse(self, response):
            # response为百度的响应对象,提取"百度一下,你就知道"
            # r_list: [<selector xpath='',data=''>]
            # extract(): ["百度一下,你就知道"]
            # extract_first(): "百度一下,你就知道"
            # 1.6版本后可使用get(): "百度一下,你就知道"
            r_list = response.xpath('/html/head/title/text()').get()
    
            print('*'*50)
            print(r_list)
            print('*'*50)

    3、全局配置settings.py

    USER_AGENT = 'Mozilla/5.0'
    ROBOTSTXT_OBEY = False
    DEFAULT_REQUEST_HEADERS = {
    'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
    'Accept-Language': 'en',
    }

    或者把USER_AGENT文件写道头文件里面

    DEFAULT_REQUEST_HEADERS = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Language': 'en',
        'USER_AGENT':'Mozilla/5.0',
    }

    4、创建begin.py(和scrapy.cfg同目录)

    from scrapy import cmdline
    
    cmdline.execute('scrapy crawl baidu'.split())

    5、启动爬虫

    直接运行 begin.py 文件即可

    猫眼电影案例

    目的

    • URL: 百度搜索 -> 猫眼电影 -> 榜单 -> top100榜
    • 爬取内容:电影名称、电影主演、上映时间

    实现步骤

    1、创建项目和爬虫文件

    创建爬虫项目  scrapy startproject Maoyan
            cd Maoyan
    创建爬虫文件  scrapy genspider maoyan maoyan.com

    2、定义要爬取的数据结构(items.py)

    name = scrapy.Field()
    star = scrapy.Field()
    time = scrapy.Field()

    3、编写爬虫文件(maoyan.py)

    1、基准xpath,匹配每个电影信息节点对象列表
      dd_list = response.xpath('//dl[@class="board-wrapper"]/dd')
    2、for dd in dd_list:
      电影名称 = dd.xpath('./a/@title')
      电影主演 = dd.xpath('.//p[@class="star"]/text()')
      上映时间 = dd.xpath('.//p[@class="releasetime"]/text()')

    代码实现一

    下载速度慢,爬了一页再爬第二页,调度器里面只有一个地址。

    # -*- coding: utf-8 -*-
    import scrapy
    from ..items import MaoyanItem
    
    
    class MaoyanSpider(scrapy.Spider):
        name = 'maoyan'  # 爬虫名
        allowed_domains = ['maoyan.com']  # 允许爬虫的域名
        start_urls = ['https://maoyan.com/board/4?offset=0']  # 起始的URL地址
        offset = 0
    
        def parse(self, response):
            # 给items.py中的类:MaoyanItem(scrapy.Item)实例化
            item = MaoyanItem()
    
            # 基准xpath,匹配每个电影信息节点对象列表
            dd_list = response.xpath('//dl[@class="board-wrapper"]/dd')
            # 依次遍历
            for dd in dd_list:
                # [<selector xpath='' data='霸王别姬'>]
                # dd.xpath('')结果为[选择器1,选择器2]
                # .extract() 把[选择器1,选择器2]所有选择器序列化为unicode字符串
                # .extract_first() : 取第一个字符串
                # 是在给items.py中那些类变量赋值
                item['name'] = dd.xpath('./a/@title').get().strip()
                item['star'] = dd.xpath('.//p[@class="star"]/text()').get().strip()
                item['time'] = dd.xpath('.//p[@class="releasetime"]/text()').get().strip()
    
                # 把item对象交给管道文件处理
                yield item
    
            # 此方法不推荐,效率低
            self.offset += 10
            if self.offset <= 91:
                url = 'https://maoyan.com/board/4?offset={}'.format(self.offset)
                # 交给调度器入队列
                yield scrapy.Request(
                    url=url,
                    callback=self.parse)

    代码实现二,基于下载器是多线程的,把多个地址,一次性的都给调度器,请求指纹,第一个地址爬了两次

    # -*- coding: utf-8 -*-
    import scrapy
    from ..items import MaoyanItem
    
    
    class MaoyanSpider(scrapy.Spider):
        name = 'maoyan2'  # 爬虫名
        allowed_domains = ['maoyan.com']  # 允许爬取的域名
        start_urls = ['https://maoyan.com/board/4?offset=0']  # 起始的URL地址
    
        def parse(self, response):
            for offset in range(0, 91, 10):
                url = 'https://maoyan.com/board/4?offset={}'.format(offset)
                # 把地址交给调度器入队列
                yield scrapy.Request(url=url,
                                     callback=self.parse_page)
    
        def parse_page(self, response):
            # 给items.py中的类:MaoyanItem(scrapy.Item)实例化
            item = MaoyanItem()
    
            # 基准xpath,匹配每个电影信息节点对象列表
            dd_list = response.xpath('//dl[@class="board-wrapper"]/dd')
            # dd_list : [<element dd at xxx>,<...>]
    
            for dd in dd_list:
                # [<selector xpath='' data='霸王别姬'>]
                # dd.xpath('')结果为[选择器1,选择器2]
                # .extract() 把[选择器1,选择器2]所有选择器序列化为
                # unicode字符串
                # .extract_first() : 取第一个字符串
                # 是在给items.py中那些类变量赋值
                item['name'] = dd.xpath('./a/@title').get().strip()
                item['star'] = dd.xpath('.//p[@class="star"]/text()').get().strip()
                item['time'] = dd.xpath('.//p[@class="releasetime"]/text()').get().strip()
    
                # 把item对象交给管道文件处理
                yield item

    代码实现三

    # 重写start_requests()方法,直接把多个地址都交给调度器去处理
    import scrapy
    from ..items import MaoyanItem
    
    
    class MaoyanSpider(scrapy.Spider):
        name = 'maoyan3'  # 爬虫名
        allowed_domains = ['maoyan.com']  # 允许爬取的域名
    
        # 去掉start_urls变量
    
        # 重写start_requests()方法,把所有URL地址都交给调度器
    # 去掉start_urls
    def start_requests(self): for offset in range(0, 91, 10): url = 'https://maoyan.com/board/4?offset={}'.format(offset) yield scrapy.Request(url=url, callback=self.parse) # 把地址交给调度器入队列 def parse(self, response): item = MaoyanItem() # 给items.py中的类:MaoyanItem(scrapy.Item)实例化 # 基准xpath dd_list = response.xpath('//dl[@class="board-wrapper"]/dd') # 依次遍历 for dd in dd_list: # [<selector xpath='' data='霸王别姬'>] # dd.xpath('')结果为[选择器1,选择器2] # .extract() 把[选择器1,选择器2]所有选择器序列化为 # unicode字符串 # .extract_first() : 取第一个字符串 # 是在给items.py中那些类变量赋值 item['name'] = dd.xpath('./a/@title').get().strip() item['star'] = dd.xpath('.//p[@class="star"]/text()').get().strip() item['time'] = dd.xpath('.//p[@class="releasetime"]/text()').get().strip() yield item # 把item对象交给pipline管道文件处理

    3、定义管道文件(pipelines.py)

    # -*- coding: utf-8 -*-
    
    # Define your item pipelines here
    #
    # Don't forget to add your pipeline to the ITEM_PIPELINES setting
    # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
    import pymysql
    from .settings import *
    
    
    class MaoyanPipeline(object):
        # item: 从爬虫文件maoyan.py中yield的item数据
        def process_item(self, item, spider):
            print(item['name'], item['time'], item['star'])
    
            return item
    
    
    # 新建自定义管道 - 存入MySQL数据库
    class MaoyanMysqlPipeline(object):
        # 爬虫项目开始运行时执行此函数
        def open_spider(self, spider):
            print('我是open_spider函数输出')
            # 一般用于建立数据库连接
            self.db = pymysql.connect(
                host=MYSQL_HOST,
                user=MYSQL_USER,
                password=MYSQL_PWD,
                database=MYSQL_DB,
                charset=MYSQL_CHAR)
            self.cursor = self.db.cursor()
    
        def process_item(self, item, spider):
            # 因为execute()的第二个参数为列表
            L = [item['name'].strip(),
                 item['star'].strip(),
                 item['time'].strip()]
            self.cursor.execute('insert into filmtab values(%s,%s,%s)', L)
            self.db.commit()  # 提交到数据库
    
            return item
    
        # 爬虫项目结束时执行此函数,只执行一次
        def close_spider(self, spider):
            print('我是close_spider函数输出')
            # 一般用于断开数据库连接
            self.cursor.close()
            self.db.close()

    5、全局配置文件(settings.py)

    ROBOTSTXT_OBEY = False
    DEFAULT_REQUEST_HEADERS = {
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
        'Accept-Language': 'en',
        '’USER_AGENT' = 'Mozilla/5.0'
    }
    ITEM_PIPELINES = {
    # 300表示优先级(1-1000),数字越小,优先级越高
    'Maoyan.pipelines.MaoyanPipeline': 300, 'Maoyan.pipelines.MaoyanMysqlPipeline': 200}

    6、创建并运行文件(begin.py)

    from scrapy import cmdline
    cmdline.execute('scrapy crawl maoyan'.split())

    爬虫项目启动方式

    方式一

    从爬虫文件(spider)的start_urls变量中遍历URL地址,把下载器返回的响应对象(response)交给爬虫文件的parse()函数处理

    # start_urls = ['http://www.baidu.com/']

    方式二

    重写start_requests()方法,从此方法中获取URL,交给指定的callback解析函数处理

    1、去掉start_urls变量

    2、def start_requests(self):

         # 生成要爬取的URL地址,利用scrapy.Request()方法交给调度器 **

    知识点汇总

    response.xpath('')调用方法

    结果:列表,元素为选择器 ['<selector xpath='' data='A'>]

    .extract() :提取文本内容,序列化列表中所有选择器为Unicode字符串 ['A','B','C']

    .extract_first() 或者 get() :获取列表中第1个序列化的元素(字符串)

    .get():提取列表中第1个文本内容

    response.text:获取响应内容

    response.body:获取bytes数据类型

    response.xpath('')

    pipelines.py中必须由1个函数叫process_item

    def process_item(self,item,spider):
        return item ( * 此处必须返回 item )

    日志变量及日志级别(settings.py)

    # 日志相关变量

    LOG_LEVEL = ''

    LOG_LEVEL = 'INFO'  # 表示终端只显示INFO和INF日志级别以上的信息,DEBUG就不会显示了

    LOG_FILE :      本来应该输出在终端的信息,写入到了log日志文件中

    LOG_FILE = '文件名.log'

    # 日志级别

    5 CRITICAL :严重错误

    4 ERROR    :普通错误

    3 WARNING  :警告

    2 INFO     :一般信息

    1 DEBUG    :调试信息

    settings.py常用变量

    LOG_LEVEL = ''              # 1、设置日志级别
    LOG_FILE = ''               # 2、保存到日志文件(不在终端输出)
    FEED_EXPORT_ENCODING = ''   # 3、设置数据导出编码(主要针对于json文件)
    IMAGES_STORE = '路径'        # 4、非结构化数据存储路径
    USER_AGENT = ''             # 5、设置User-Agent
    CONCURRENT_REQUESTS = 32    # 6、设置最大并发数(默认为16)
    
    # 7、下载延迟时间(每隔多长时间请求一个网页)
    # DOWNLOAD_DELAY 会影响 CONCURRENT_REQUESTS,不能使并发显现
    # 有CONCURRENT_REQUESTS,没有DOWNLOAD_DELAY: 服务器会在同一时间收到大量的请求
    # 有CONCURRENT_REQUESTS,有DOWNLOAD_DELAY 时,服务器不会在同一时间收到大量的请求
    DOWNLOAD_DELAY = 3
    
    DEFAULT_REQUEST_HEADERS = {}    # 8、请求头
    ITEM_PIPELINES = {}             # 9、添加项目管道
    DOWNLOADER_MIDDLEWARES = {}     # 10、添加下载器中间件

    管道处理数据流程

    1、在爬虫文件中为items.py中类做实例化,用爬下来的数据给对象赋值

    from ..items import MaoyanItem

    item = MaoyanItem()

    item['name'] = xxx

    2、管道文件(pipelines.py)
    3、开启管道(settings.py)
    ITEM_PIPELINES = { '项目目录名.pipelines.类名':优先级 }

    优先级1-1000,数字越小优先级越高

    scrapy.Request()参数

    1、url

    2、callback

    3、meta:传递数据,定义代理

    数据持久化存储(MySQL)

    实现步骤

    1、在setting.py中定义MYSQL相关变量

    # 定义MySQL相关变量
    MYSQL_HOST = '127.0.0.1'
    MYSQL_USER = 'root'
    MYSQL_PWD = '123456'
    MYSQL_DB = 'maoyandb'
    MYSQL_CHAR = 'utf8'

    2、pipelines.py中新建管道类,并导入settings模块from .settings import *

    # 新建自定义管道 - 存入MySQL数据库
    class MaoyanMysqlPipeline(object):
        # 爬虫程序启动时,只执行1次,一般用于数据库连接
        def open_spider(self, spider):
            print('我是open_spider函数输出')
            # 一般用于建立数据库连接
            self.db = pymysql.connect(
                host=MYSQL_HOST,
                user=MYSQL_USER,
                password=MYSQL_PWD,
                database=MYSQL_DB,
                charset=MYSQL_CHAR)
            self.cursor = self.db.cursor()
    
        def process_item(self, item, spider):
            # 用于处理爬取的item数据,这个函数一定要有
            # 因为execute()的第二个参数为列表
            L = [item['name'].strip(),
                 item['star'].strip(),
                 item['time'].strip()]
            self.cursor.execute('insert into filmtab values(%s,%s,%s)', L)
            self.db.commit()    # 提交到数据库
    
            return item
    
        # 爬虫项目结束时执行此函数,只执行一次,一般用于断开数据库连接
        def close_spider(self, spider):
            print('我是close_spider函数输出')
            # 一般用于断开数据库连接
            self.cursor.close()
            self.db.close()

    注意 :process_item() 函数中一定要 return item

    3、settings.py中添加此管道

    ITEM_PIPELINES = {
        'Maoyan.pipelines.MaoyanPipeline': 300,
        'Maoyan.pipelines.MaoyanMysqlPipeline': 200  # 数据库的管道
     }

    注意 :process_item() 函数中一定要 return item,因为第一个管道返回的item会继续交由下一个管道处理,否则返回并传入下一个管道的值为None

    保存为csv、json文件

    scrapy crawl maoyan -o maoyan.csv
    scrapy crawl maoyan -o maoyan.json

    # 在存json文件的时候,要在setting.py设置到处编码 FEED_EXPORT_ENCODING = 'utf-8'

    盗墓笔记小说抓取案例(三级页面)

    目标

    # 抓取目标网站中盗墓笔记1-8中所有章节的所有小说的具体内容,保存到本地文件
    1、网址 :http://www.daomubiji.com/

    准备工作xpath

    1、一级页面xpath(此处响应做了处理):

      盗墓笔记1-8的链接://ul[@class="sub-menu"]/li/a/@href

    2、二级页面xpath:/html/body/section/div[2]/div/article

      基准xpath ://article

      链接:./a/@href

      标题:./a/text()  # 七星鲁王 第一章 血尸

    3、三级页面xpath:

      response.xpath('//article[@class="article-content"]//p/text()').extract()

    项目实现

    1、创建项目及爬虫文件

    创建项目 :scrapy startproject Daomu
    创建爬虫 :scrapy genspider daomu www.daomubiji.com

    2、定义要爬取的数据结构(把数据交给管道)items.py

    import scrapy
    ​
    class DaomuItem(scrapy.Item):
        juan_name = scrapy.Field()    # 卷名
        zh_num = scrapy.Field()       # 章节数
        zh_name = scrapy.Field()      # 章节名
        zh_link = scrapy.Field()      # 章节链接
        zh_content = scrapy.Field()   # 小说内容

    3、爬虫文件实现数据抓取 daomu.py

    # -*- coding: utf-8 -*-
    import scrapy
    from ..items import DaomuItem
    ​
    class DaomuSpider(scrapy.Spider):
        name = 'daomu'
        allowed_domains = ['www.daomubiji.com']
        start_urls = ['http://www.daomubiji.com/']
    ​
        # 解析一级页面,提取 盗墓笔记1 2 3 ... 链接
        def parse(self, response):
            one_link_list = response.xpath('//ul[@class="sub-menu"]/li/a/@href').extract()
            print(one_link_list)
            # 把链接交给调度器入队列
            for one_link in one_link_list:
                yield scrapy.Request(url=one_link, callback=self.parse_two_link, dont_filter=True)
    ​
        # 解析二级页面
        def parse_two_link(self,response):
            # 基准xpath,匹配所有章节对象列表
            article_list = response.xpath('/html/body/section/div[2]/div/article')
            # 依次获取每个章节信息
            for article in article_list:
                # 创建item对象
                item = DaomuItem()
                info = article.xpath('./a/text()').extract_first().split()
                # info : ['七星鲁王','第一章','血尸']
                item['juan_name'] = info[0]
                item['zh_num'] = info[1]
                item['zh_name'] = info[2]
                item['zh_link'] = article.xpath('./a/@href').extract_first()
                # 把章节链接交给调度器
                yield scrapy.Request(
                    url=item['zh_link'],
                    # 把item传递到下一个解析函数
                    meta={'item':item},
                    callback=self.parse_three_link,
                    dont_filter=True
                )
    ​
        # 解析三级页面
        def parse_three_link(self,response):
            # 获取上一个函数传递过来的item对象
            item = response.meta['item']
            # 获取小说内容
            # ['段落1','段落2','段落3',....]
            item['zh_content'] = '
    '.join(response.xpath(
              '//article[@class="article-content"]//p/text()'
            ).extract())
    
    ​        # 所有的数据都爬完了,再yield
            yield item
    ​
            # '
    '.join(['第一段','第二段','第三段'])    

    4、管道文件实现数据处理pipline.py

    # -*- coding: utf-8 -*-
    # Define your item pipelines here
    #
    # Don't forget to add your pipeline to the ITEM_PIPELINES setting
    # See: https://doc.scrapy.org/en/latest/topics/item-pipeline.html
    ​
    ​
    class DaomuPipeline(object):
        def process_item(self, item, spider):
            filename = '/home/tarena/aid1902/{}-{}-{}.txt'.format(
                item['juan_name'],
                item['zh_num'],
                item['zh_name']
            )
    ​
            f = open(filename,'w')
            f.write(item['zh_content'])
            f.close()
            return item

    5、setting

      打开通道

    腾讯招聘

    MySQL数据库--建库建表

    create database tencentdb charset utf8;
    use tencentdb;
    create table tencenttab(
            name varchar(100),
            type varchar(100),
            duty varchar(5000),
            requirement varchar(5000)
            )charset=utf8;

    1、创建项目+爬虫文件

    scrapy startproject Tencent
    cd Tencent
    scrapy genspider tencent hr.tencent.com

    2、定义爬取的数据结构 items.py

    job_name = scrapy.Field()
    job_type = scrapy.Field()    # 类别
    job_duty = scrapy.Field()    # 职责
    job_require = scrapy.Field()    # 要求
    job_address = scrapy.Field()    # 地址

    3、爬虫文件

    class TencentSpider(scrapy.Spider):
        name = 'tencent'
        allowed_domains = ['careers.tencent.com']
        one_url = 'https://careers.tencent.com/tencentcareer/api/post/Query?timestamp=1563912271089&countryId=&cityId=&bgIds=&productId=&categoryId=&parentCategoryId=&attrId=&keyword=&pageIndex={}&pageSize=10&language=zh-cn&area=cn'
        two_url = 'https://careers.tencent.com/tencentcareer/api/post/ByPostId?timestamp=1563912374645&postId={}&language=zh-cn'
        # 1. 去掉start_urls
        # 2. 重新start_requests()方法
        def start_requests(self):
            total_page = self.get_total_page()
            for page_index in range(1,total_page):
                url = self.one_url.format(page_index)
                yield scrapy.Request(
                    url = url,
                    callback = self.parse_one
                )
    ​
        # 获取总页数
        def get_total_page(self):
            url = self.one_url.format(1)
            html = requests.get(url=url).json()
            total_page = int(html['Data']['Count']) // 10 + 1return total_page
    ​
        # 解析一级页面函数
        def parse_one(self,response):
            html = json.loads(response.text)
            for job in html['Data']['Posts']:
                item = TencentItem()
                # postId: 拼接二级页面的地址
                post_id = job['PostId']
                two_url = self.two_url.format(post_id)
                # 交给调度器
                yield scrapy.Request(
                    url = two_url,
                    meta = {'item':item},
                    callback = self.parse_two_page
                )
    ​
        def parse_two_page(self,response):
            item = response.meta['item']
            html = json.loads(response.text)
            item['job_name'] = html['Data']['RecruitPostName']
            item['job_type'] = html['Data']['CategoryName']
            item['job_duty'] = html['Data']['Responsibility']
            item['job_require'] = html['Data']['Responsibility']
            item['job_address'] = html['Data']['LocationName']
    ​
    ​
            yield item

    4、管道文件

    create database tencentdb charset utf8;
    use tencentdb;
    create table tencenttab(
            job_name varchar(500),
            job_type varchar(100),
            job_duty varchar(1000),
            job_require varchar(1000),
            job_address varchar(100)
            )charset=utf8;

    管道文件pipelines实现

    import pymysql
    class TencentMysqlPipeline(object):
        def open_spider(self,spider):
            self.db = pymysql.connect(
                '127.0.0.1','root','123456','tencentdb',
                charset='utf8'
            )
            self.cursor = self.db.cursor()
    ​
        def process_item(self,item,spider):
            ins = 'insert into tencenttab values(%s,%s,%s,%s,%s)'
            job_list = [
                item['job_name'],item['job_type'],item['job_duty'],
                item['job_require'],item['job_address']
            ]
            self.cursor.execute(ins,job_list)
            self.db.commit()
            return item
    ​
        def close_spider(self,spider):
            self.cursor.close()
            self.db.close()

    5、settings.py

    定义常用变量,添加管道即可

    图片管道(360图片抓取案例)

    目标:www.so.com -> 图片 -> 美女

    抓取网络数据包

    2、F12抓包,抓取到json地址 和 查询参数(QueryString)
         url = 'http://image.so.com/zj?ch=beauty&sn={}&listtype=new&temp=1'.format(str(sn))
         ch: beauty
         sn: 90
         listtype: new
         temp: 1

    项目实现

    1、创建爬虫项目和爬虫文件

    scrapy startproject So
    cd So
    scrapy genspider so image.so.com

    2、定义要爬取的数据结构(items.py)

    img_link = scrapy.Field()

    3、爬虫文件实现图片链接抓取

    # -*- coding: utf-8 -*-
    import scrapy
    import json
    from ..items import SoItem
    ​
    class SoSpider(scrapy.Spider):
        name = 'so'
        allowed_domains = ['image.so.com']
    ​
        # 重写Spider类中的start_requests方法
        # 爬虫程序启动时执行此方法,不去找start_urls
        def start_requests(self):
            for page in range(5):
                url = 'http://image.so.com/zj?ch=beauty&sn={}&listtype=new&temp=1'.format(str(page*30))
                # 把url地址入队列
                yield scrapy.Request(
                    url = url,
                    callback = self.parse_img
                )
    ​
        def parse_img(self, response):
            html = json.loads(response.text)
    ​
            for img in html['list']:
                item = SoItem()
                # 图片链接
                item['img_link'] = img['qhimg_url']
    ​
                yield item

    4、管道文件(pipelines.py)

    from scrapy.pipelines.images import ImagesPipeline
    import scrapy
    ​
    class SoPipeline(ImagesPipeline):
        # 重写get_media_requests方法
        def get_media_requests(self, item, info):
            yield scrapy.Request(item['img_link'])

    5、设置settings.py

    IMAGES_STORE = '/home/tarena/images/'

    6、创建run.py运行爬虫

    scrapy shell的使用

    基本使用

    1. scrapy shell URL地址
    2. request.headers :请求头(字典)
    3. reqeust.meta    :item数据传递,定义代理(字典)
    4. response.text    :字符串
    5. response.body    :bytes
    6. response.xpath('')

    scrapy.Request()

    1. url
    2. callback
    3. headers
    4. meta :传递数据,定义代理
    5. dont_filter :是否忽略域组限制,默认False检查域组限制allowed_domains['']

    设置中间件(随机User-Agent)

    少量User-Agent切换

    方法一

    # settings.py
    USER_AGENT = ''
    DEFAULT_REQUEST_HEADERS = {}

    方法二

    # spider
    yield scrapy.Request(url,callback=函数名,headers={})

    大量User-Agent切换(中间件)

    middlewares.py设置中间件

    1、获取User-Agent

      # 方法1 :新建useragents.py,存放大量User-Agent,random模块随机切换

      # 方法2 :安装fake_useragent模块(sudo pip3 install fack_useragent)

    from fake_useragent import UserAgent
    
    ua_obj = UserAgent()
    ua = ua_obj.random

    2、middlewares.py新建中间件类,拦截传给下载器的请求内容

    class RandomUseragentMiddleware(object):
        def process_request(self,reuqest,spider):
            ua = UserAgent()
            request.headers['User-Agent'] = ua.random    

    3、settings.py添加此下载器中间件

    DOWNLOADER_MIDDLEWARES = {
        'Baidu.middlewares.TestDownloaderMiddleware': 543,
        'Baidu.middlewares.RandomUaDownloaderMiddleware': 300,
        'Baidu.middlewares.TestRandomProxyMiddleware': 400,
    }

    设置中间件(随机代理)

    import random
    from fake_useragent import UserAgent
    
    
    # 随机User-Agent下载器中间件
    class RandomUaDownloaderMiddleware(object):
        def process_request(self, request, spider):
            # 给每一个拦截下来的请求包装随机User-Agent
            ua = UserAgent()
            useragent = ua.random
            # request.headers: 字典
            request.headers['User-Agent'] = useragent
    
            print('我是中间件:', useragent)  # 测试
    
    proxy_list = ['http://1.1.1.1:1111', 'http://2.2.2.2:2222']
    
    # 随机代理IP下载器中间件
    class TestRandomProxyMiddleware(object):
        def process_request(self, request, spider):
            proxy = random.choice(proxy_list)  # 1. 随机选择并定义好代理
            request.meta['proxy'] = proxy  # 2. 如何包装
            print('我是中间件2:', proxy)  # 测试
    
        # 处理异常,一旦代理不能用,则返回请求再次执行下载器中间件,把请求扔回调度器
        def process_exception(self, request, exception, spider):
            return request
  • 相关阅读:
    条件类的设计
    条件对象的设计
    又是一个星期天,明天又要开始一周的工作了,想想上周的工作情况,不怎么理想。
    自动设置的类,版本2,在设计上比前一个版本有进步。
    最近写了一个自动保存设置的类。
    关于异常信息"未找到成员"
    表达式类的设计
    IExtenderProvider 接口的应用.实现自定义组件LilyValidateProvider
    IIS404的问题
    程序开发[对象的旅行]
  • 原文地址:https://www.cnblogs.com/LXP-Never/p/11391283.html
Copyright © 2020-2023  润新知