­

scrapy爬虫框架

  • 2019 年 10 月 3 日
  • 筆記

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