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\'] = \'\n\'.join(response.xpath(
          \'//article[@class="article-content"]//p/text()\'
        ).extract())

​        # 所有的数据都爬完了,再yield
        yield item
​
        # \'\n\'.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

 

版权声明:本文为LXP-Never原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/LXP-Never/p/11391283.html