scrapy爬虫框架
scrapy框架是异步处理框架,可配置和可扩展程度非常高,Python中使用最广泛的爬虫框架。
安装
Ubuntu安装
1、安装依赖包
- sudo apt-get install libffi-dev
- sudo apt-get install libssl-dev
- sudo apt-get install libxml2-dev
- sudo apt-get install python3-dev
- sudo apt-get install libxslt1-dev
- sudo apt-get install zlib1g-dev
- sudo pip3 install -I -U service_identity
2、安装scrapy框架
- sudo pip3 install Scrapy
Windows安装
cmd命令行(管理员): python -m pip install Scrapy
Scrapy框架五大组件
- 引擎(Engine) :整个框架核心
- 调度器(Scheduler) :维护请求队列
- 下载器(Downloader) :获取响应对象,下载器是基于多线程的
- 爬虫文件(Spider) :数据解析提取
- 项目管道(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
}
创建爬虫项目步骤
- 新建项目 :scrapy startproject 项目名
- cd 项目文件夹
- 新建爬虫文件 :scrapy genspider 文件名 域名
- 明确目标(items.py)
- 写爬虫程序(文件名.py)
- 管道文件(pipelines.py)
- 全局配置(settings.py)
- 运行爬虫 :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 + 1 return 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的使用
基本使用
- scrapy shell URL地址
- request.headers :请求头(字典)
- reqeust.meta :item数据传递,定义代理(字典)
- response.text :字符串
- response.body :bytes
- response.xpath(\’\’)
scrapy.Request()
- url
- callback
- headers
- meta :传递数据,定义代理
- 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