python爬虫快速入门之—Scrapy 从入门到包吃包住
文章目录
- python爬虫快速入门之---Scrapy 从入门到包吃包住
- 一、scrapy简介
- 1.1、scrapy是什么?
- 1.2、Scrapy 的特点
- 1.3、Scrapy 的主要组件
- 1.4、Scrapy 工作流程
- 1.5、scrapy的安装
- 二、scrapy项目快速入门
- 2.1、scrapy项目快速创建以及运行
- 2.1.1、创建爬虫项目
- 2.1.2、创建爬虫文件
- 2.1.3、运行爬虫代码
- 2.1.4、修改遵守robots协议
- 2.2、scrapy项目
- 2.2.1、文件结构
- 2.2.2、parse方法中的response属性和方法
- 2.2.3、scrapy的工作原理
- 2.3、yield关键字
- 三、scrapy shell
- 3.1、scrapy shell简介
- 3.2、进入scrapy shell
- 3.3、scrapy shell的基本使用
- 四、scrapy项目实战--抓取商品数据并保存
- 4.1、创建项目
- 4.2、定义item数据结构
- 4.3、编写爬虫文件
- 4.4、编写pipeline管道
- 4.5、单管道运行查看
- 4.6、多管道的编写
- 4.6.1、定义广告类
- 4.6.2、在setting中开启管道
- 4.6.3、启动测试
- 4.7、下载多页数据
- 五、scrapy项目实战--网页嵌套处理
- 六、CrawlSpider
- 6.1、简介
- 6.2、链接提取器
- 七、CrawlSpider案例实战
- 7.1、项目初始化
- 7.2、改造项目
- 7.3、运行并查看结果
- 八、联动mysql数据库持久化到本地
- 8.1、安装pymysql
- 8.2、创建mysql数据库
- 8.3、编写配置
- 8.4、编写数据库持久化管道类
- 8.5、开启管道
- 8.6、测试并观察数据库中保存的结果
- 九、日志与日志文件
- 十、scrapy的post请求
- 十一、scrapy的代理
- 11.1、 **在 `settings.py` 中配置代理**
- 11.2、 **自定义代理中间件**
- 11.3、 **为特定请求设置代理**
- 11.4、 **使用第三方代理服务**
一、scrapy简介
1.1、scrapy是什么?
官方文档:https://scrapy.org/
scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。
可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。
Scrapy 是一个开源的 Python 爬虫框架,用于从网站上提取数据(即进行网络爬虫),并能将这些数据进行处理和存储。
它的设计目标是简单高效地抓取大量网页,并提供强大的工具来进行数据的提取和分析。
1.2、Scrapy 的特点
- 快速开发:Scrapy 提供了许多内置功能,帮助开发者快速构建高效的爬虫程序。
- 可扩展性强:它允许用户自定义中间件、管道等,满足各种爬虫需求。
- 异步处理:Scrapy 使用 Twisted 异步网络库,可以同时处理大量请求,从而加快爬虫的效率。
- 数据处理方便:支持将数据保存为多种格式,例如 JSON、CSV、XML 等。
1.3、Scrapy 的主要组件
- Spider(爬虫):这是用户定义的类,用于指定如何从某个或多个网站抓取数据以及如何解析和处理这些数据。
- Selectors(选择器):Scrapy 提供了强大的选择器工具(如 XPath、CSS 选择器),用于从 HTML 页面中提取数据。
- Item(数据容器):类似于一个数据结构,用来定义要从网页中抓取和存储的数据。
- Pipeline(数据管道):用于对抓取到的数据进行后续处理,如清洗、验证、存储等。
- Middleware(中间件):在请求和响应的处理中,可以通过中间件对其进行拦截和处理,比如修改 headers、处理 cookies 等。
1.4、Scrapy 工作流程
- 发送请求:Spider 定义了要抓取的网站地址。Scrapy 通过异步方式发送请求。
- 接收响应:收到响应后,通过 Spider 定义的回调方法处理响应数据。
- 数据提取:利用 Scrapy 提供的选择器工具提取目标数据。
- 保存数据:提取到的数据会通过管道处理,进行清洗、存储或输出
1.5、scrapy的安装
懒得记笔记,直接上连接:https://blog.csdn.net/qq_45476428/article/details/108739943
- 如果报错twisted:
http://www.1fd.uci.edu/~gohlke/pythonlibs/#twisted - 也可以使用anaconda安装环境:
https://docs.anaconda.com/anaconda/install/windows
二、scrapy项目快速入门
2.1、scrapy项目快速创建以及运行
2.1.1、创建爬虫项目
切换到一个你想存放项目的文件夹,并进入命令行,使用命令来创建一个scrapy项目。
命令如下:
scrapy startproject scrapy_study_01
其中scrapy_study_01
是项目的名字,项目的名字不允许使用数字开头,也不能包含中文。
从而可以在目录下看到这个项目:
然后使用我们的ide来打开这个项目:
2.1.2、创建爬虫文件
要在spiders文件夹中去创建爬虫文件
命令:cd 项目的名字\项目的名字\spiders
cd scrapy_study_01\scrapy_study_01\spiders
创建爬虫文件:scrapy genspider 爬虫文件的名字 要爬取网页
scrapy genspider baidu http://www.baidu.com
一般情况下不需要添加http协议
可以看到新创建的文件:
import scrapy
class BaiduSpider(scrapy.Spider):
# 爬虫名称
name = "baidu"
# 允许的域名
allowed_domains = ["www.baidu.com"]
# 起始url 在allowed_domains的前面添加了http://
start_urls = ["http://www.baidu.com"]
# 是执行了start_urls之后 执行的方法 方法中的response就是返回的那个对象
# 相当于response = urllib.request.urlopen()
# 和 response = requests.get()
def parse(self, response):
print("我是一个百度的爬虫程序")
2.1.3、运行爬虫代码
语法:scrapy crawl 爬虫的名字
scrapy crawl baidu
当我运行爬虫的代码的时候,并没有执行我的
print("我是一个百度的爬虫程序")
语句,这可以网站就做了一些反扒的手段。怎么处理:
百度的robots.txt协议:
根据下图可以看到百度是不允许爬虫的
2.1.4、修改遵守robots协议
打开项目下的settings.py文件,把这句ROBOTSTXT_OBEY = True
代码注释即可,意为不遵守robots协议。
然后再次运行代码:
scrapy crawl baidu
发现我们的语句执行了:
2.2、scrapy项目
2.2.1、文件结构
2.2.2、parse方法中的response属性和方法
属性和方法 | 意义 |
---|---|
response.text | 获取的是响应的字符串 |
response.body | 获取的是二进制数据 |
response.xpath | 可以直接是xpath方法来解析response中的内容 |
response.extract() | 提取seletor对象的data属性值 |
response.extract_first() | 取的seletor列表的第-个数据 |
可以使用下面这个58同城的案例来测试:
-
创建项目
scrapy startproject scrapy_study_02
-
创建爬虫文件
cd scrapy_study_02\scrapy_study_02\spiders
scrapy genspider tc "https://bj.58.com/sou/?key=%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91&classpolicy=uuid_c84b556016c34f2392cf3772a0ff84d3%2Cclassify_B&search_uuid=c84b556016c34f2392cf3772a0ff84d3"
上述网址来源于:58同城
-
修改遵守robots协议
修改tc.py文件来查看response参数里面的内容:
import scrapy
class TcSpider(scrapy.Spider):
name = "tc"
allowed_domains = ["bj.58.com"]
start_urls = ["https://bj.58.com/sou/?key=%E5%89%8D%E7%AB%AF%E5%BC%80%E5%8F%91&classpolicy=uuid_c84b556016c34f2392cf3772a0ff84d3%2Cclassify_B&search_uuid=c84b556016c34f2392cf3772a0ff84d3"]
def parse(self, response):
html= response.text
print("*******************************")
print(html)
运行python文件:
scrapy crawl tc
查看控制台的打印结果,发现就是我们需要的网页:
所以现在总结一下response的属性和方法:
属性和方法 | 意义 |
---|---|
response.text | 获取的是响应的字符串 |
response.body | 获取的是二进制数据 |
response.xpath | 可以直接是xpath方法来解析response中的内容 |
response.extract() | 提取seletor对象的data属性值 |
response.extract_first() | 取的seletor列表的第-个数据 |
2.2.3、scrapy的工作原理
引擎(Engine)
引擎负责控制数据流在系统中所有组件中流动,并在相应动作发生时触发事件。 详细内容查看下面的数据流(Data Flow)
部分。
调度器(Scheduler)
调度器从引擎接受request
并将他们入队,以便之后引擎请求他们时提供给引擎。
下载器(Downloader)
下载器负责获取页面数据并提供给引擎,而后提供给spider
。
爬虫(Spiders)
Spider
是Scrapy
用户编写用于分析response
并提取item
(即获取到的item)或额外跟进的URL的类。 每个spider
负责处理一个特定(或一些)网站。
项目管道(Item Pipeline)
Item Pipeline
负责处理被spider
提取出来的item
。典型的处理有清理、 验证及持久化(例如存取到数据库中)。
下载器中间件(Downloader middlewares)
下载器中间件是在引擎及下载器之间的特定钩子(specific hook)
,处理Downloader
传递给引擎的response
。 其提供了一个简便的机制,通过插入自定义代码来扩展Scrapy
功能。
爬虫中间件(Spider middlewares)
Spider中间件
是在引擎及Spider之间的特定钩子(specific hook)
,处理spider
的输入(response)和输出(items及requests)。 其提供了一个简便的机制,通过插入自定义代码来扩展Scrapy功能。
简言之可以总结为下面几点:
- 引擎向spiders要url
- 引擎将要爬取的ur给调度器
- 调度器会将ur生成请求象放入到指定的队列中
- 从队列中出队一个请求
- 引擎将请求交给下载器进行处理
- 下载器发送请求获取互联网数据
- 下载器将数据返回给引擎
- 引擎将数据再次给到spiders
- spiders通过xpath解析该数据,得到数据或者url
- spiders将数据或者url给到引擎
- 引擎判断该数据还是url,是数据,交给管道(item pipeline)处理,是url交给调度器处理
2.3、yield关键字
- 带有yield的函数不再是一个普通函数,而是一个生成器generator,可用于迭代
- yield是一个类似return的关键字,迭代一次遇到yield时就返回yield后面(右边)的值。重点是:下一次迭代时,从上一次迭代遇到的yield后面的代码(下一行)开始执行
- 简要理解:yield就是return返回一个值,并且记住这个返回的位置,下次迭代就从这个位置后(下一行)开始
三、scrapy shell
3.1、scrapy shell简介
Scrapy shell是一个交互式shell(终端),您可以在其中快速调试您的抓取代码,而无需运行spider。它旨在用于测试数据提取代码,但您实际上可以将其用于测试任何类型的代码,因为它也是一个常规的Python shell。
shell用于测试XPath或CSS表达式,看看它们是如何工作的,以及它们从您试图抓取的网页中提取了什么数据。它允许您在编写spider时交互式地测试表达式,而无需运行spider来测试每一个更改。
一旦你熟悉了Scrapy shell,你就会发现它是开发和调试spider的宝贵工具。
scrapy shell官方文档
3.2、进入scrapy shell
进入到scrapy shell的终端直接在window的终端中输入scrapy shell 域名
即:
scrapy shell www.baidu.com
如果想看到一些高亮或者自动补全那么可以安装ipython,使用命令安装:
pip install ipython
3.3、scrapy shell的基本使用
可用的方法
shelp()
: 打印可用的对象和方法fetch(url[, redirect=True])
: 爬取新的 URL 并更新所有相关对象fetch(request)
: 通过给定request 爬取,并更新所有相关对象view(response)
: 使用本地浏览器打开给定的响应。这会在计算机中创建一个临时文件,这个文件并不会自动删除
可用的Scrapy对象
Scrapy shell自动从下载的页面创建一些对象,如 Response 对象和 Selector 对象。这些对象分别是
crawler
: 当前Crawler 对象spider
: 爬取使用的 Spider,如果没有则为Spider对象request
: 最后一个获取页面的Request对象,可以使用 replace() 修改请求或者用 fetch() 提取新请求response
: 最后一个获取页面的Response对象settings
: 当前的Scrapy设置
例如使用response
:
-
response.body
-
response.text
-
response.url
-
response.status
-
response.xpath('//input[@id="su"]/@value')
四、scrapy项目实战–抓取商品数据并保存
案例背景: 获取一个购物网页的一些数据,例如标题、图片、价格等。
4.1、创建项目
根据本篇博客的2.1部分内容来进行创建,其中创建爬虫文件关键的语句为:
scrapy genspider dang https://category.dangdang.com/cp01.01.01.00.00.00.html
4.2、定义item数据结构
# Define here the models for your scraped items
#
# See documentation in:
# https://docs.scrapy.org/en/latest/topics/items.html
import scrapy
class ScrapyStudy04DangdangItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# 价格
price = scrapy.Field()
# 标题
title = scrapy.Field()
# 图片
img_url = scrapy.Field()
4.3、编写爬虫文件
import scrapy
from scrapy_study_04_dangdang.items import ScrapyStudy04DangdangItem
class DangSpider(scrapy.Spider):
name = "dang"
allowed_domains = ["category.dangdang.com"]
start_urls = ["https://category.dangdang.com/cp01.01.01.00.00.00.html"]
def parse(self, response):
# pipelines 存储数据
# item 定义数据
li_list = response.xpath("//ul[@id='component_59']/li")
for li in li_list:
title = li.xpath(".//a[1]/@title").extract_first()
price = li.xpath(".//p[3]/span[1]/text()").extract_first()
img = li.xpath(".//img/@data-original").extract_first()
if img:
img = img
else:
img = li.xpath(".//img/@src").extract_first() # 防止出现没有data-original数据的情况
book = ScrapyStudy04DangdangItem(img_url=img, title=title, price=price)
# 获取一个book就将book交给pipelines
yield book
其中通过yield关键字将我们需要的book数据对象传输到pipelines中,方便我们进行数据处理。
而关键语句book = ScrapyStudy04DangdangItem(img_url=img, title=title, price=price)
可以看出我们的语句是来自items.py
文件。
4.4、编写pipeline管道
在使用这个文件之前,需要先在setting.py中开启这个功能:
即:
# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
"scrapy_study_04_dangdang.pipelines.ScrapyStudy04DangdangPipeline": 300,
}
- 其中管道可以有很多个;
- 管道是有优先级的,优先级的范围是1-1000 ;
- 取值越小的优先级越高。
现在我们就可以将我们的数据进行处理(保存成json文件):
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# useful for handling different item types with a single interface
from itemadapter import ItemAdapter
# 如果需要使用pipeline,需要现在setting中开启
class ScrapyStudy04DangdangPipeline:
# item: yield 后面的book对象
def process_item(self, item, spider):
with open("book.json", "a", encoding="utf-8") as f:
f.write(str(item))
return item
实际操作的时候要注意以下几个问题:
(1)write里面必须传入字符串,所以需要先转成字符串
(2)写入文件的w模式,每次写入都会覆盖之前的数据,所以把w改成a(追加)
缺点:每次写入都会打开文件,然后关闭文件,效率不高
优化版pipelines:
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html
# useful for handling different item types with a single interface
from itemadapter import ItemAdapter
# 如果需要使用pipeline,需要现在setting中开启
class ScrapyStudy04DangdangPipeline:
# 爬虫文件执行之前
def open_spider(self, spider):
self.fp = open("book.json", "w", encoding="utf-8")
# item: yield 后面的book对象
def process_item(self, item, spider):
# 优化版
self.fp.write(str(item))
# 爬虫文件执行之后
def close_spider(self, spider):
self.fp.close()
经过上述这种写法的优化之后,就改变了频繁的打开和关闭文件的操作,其中两个方法分别对应的是爬虫文件执行之前和之后执行。
4.5、单管道运行查看
根据上述代码的方式来编写项目,起始就是一个单管道的一种模式。
运行结果:
4.6、多管道的编写
在上述代码的基础上,再添加一些代码即可实现多管道的编写
4.6.1、定义广告类
在pipelines.py文件上新建一个ScrapyDangdangDownloadPipeline
类,用来下载图片资源:
class ScrapyDangdangDownloadPipeline:
# 这个方法源自上面这个类的process_item方法
def process_item(self, item, spider):
url = item.get("img_url")
filename = './books/' + item.get("title") + ".jpg"
urllib.request.urlretrieve(url, filename)
return item
4.6.2、在setting中开启管道
打开settings.py
文件,找到ITEM_PIPELINES
这个参数,并在里面添加ScrapyDangdangDownloadPipeline
参数如下:
# Configure item pipelines
# See https://docs.scrapy.org/en/latest/topics/item-pipeline.html
ITEM_PIPELINES = {
# 管道可以有很多个,管道是有优先级的,优先级的范围是1-1000 值越小的优先级越高
"scrapy_study_04_dangdang.pipelines.ScrapyStudy04DangdangPipeline": 300,
# ScrapyDangdangDownloadPipeline
"scrapy_study_04_dangdang.pipelines.ScrapyDangdangDownloadPipeline": 301,
}
4.6.3、启动测试
输入命令启动多管道项目:
scrapy crawl dang
就会发现新产生的json
文件和图片资源文件:
需要注意的是,books文件夹需要手动添加。
4.7、下载多页数据
多页的爬取的业务逻辑全都是一样的,所以我们只需要将执行的那个页的请求再次调用parse方法
但是首先需要观察每页变化的逻辑:
https://category.dangdang.com/pg1-cp01.01.07.00.00.00.html
https://category.dangdang.com/pg2-cp01.01.07.00.00.00.html
https://category.dangdang.com/pg6-cp01.01.07.00.00.00.html
https://category.dangdang.com/pg100-cp01.01.07.00.00.00.html
改造原来的dang.py
文件里面的parse
函数
import scrapy
from scrapy_study_04_dangdang.items import ScrapyStudy04DangdangItem
class DangSpider(scrapy.Spider):
name = "dang"
# 这里只写域名,在旧版本上面会自动添加原始请求,但是在请求多个页面,不同接口的时候这里只能写域名
allowed_domains = ["category.dangdang.com"]
start_urls = ["https://category.dangdang.com/cp01.01.01.00.00.00.html"]
base_url = "https://category.dangdang.com/pg"
page = 1
def parse(self, response):
# pipelines 存储数据
# item 定义数据
li_list = response.xpath("//ul[@id='component_59']/li")s
for li in li_list:
title = li.xpath(".//a[1]/@title").extract_first()
# detail = li.xpath(".//p[1]/a/text()").extract_first()
price = li.xpath(".//p[3]/span[1]/text()").extract_first()
img = li.xpath(".//img/@data-original").extract_first()
if img:
img = img
else:
img = li.xpath(".//img/@src").extract_first() # 防止出现没有data-original数据的情况
book = ScrapyStudy04DangdangItem(img_url="https:" + img, title=title, price=price)
# 获取一个book就将book交给pipelines
yield book
if self.page <= 100:
url = self.base_url + str(self.page) + "-cp01.01.07.00.00.00.html"
self.page += 1
# 调用parse函数get请求
# scrapy.Request就是scrapy的
# url 就是请求地址
# callback 回调函数(即需要调用的函数,后面不用加())
yield scrapy.Request(url=url, callback=self.parse)
具体细节在上述代码的注释上面存在,请仔细阅读。
最后启动测试即可:
scrapy crawl dang
五、scrapy项目实战–网页嵌套处理
根据本篇博客的2.1部分内容来进行创建,其中创建爬虫文件关键的语句为:
scrapy genspider mv https://btwuji.com/html/gndy/index.html
起始其他逻辑都与本博客第四模块差不多,主要就是网页嵌套的请求发起,当我们点击另一个链接的时候又需要对其发起请求,大致逻辑如下:
import scrapy
from scrapy_study_05_movie.items import ScrapyStudy05MovieItem
class MvSpider(scrapy.Spider):
name = "mv"
allowed_domains = ["btwuji.com"]
start_urls = ["https://btwuji.com/html/gndy/index.html"]
def parse(self, response):
list = "//div[@class='co_content8']//td[1]/a[2]"
for i in response.xpath(list):
# 获取第二页url
url = "https://btwuji.com/" + i.xpath("./@href").extract_first()
# 获取电影名称
name = i.xpath("./text()").extract_first()
# 对第二页url进行请求
yield scrapy.Request(url=url, callback=self.parse_second, meta={"name": name})
def parse_second(self, response):
img_src = response.xpath("//div[@id='Zoom']//img/@src").extract_first() # 需要注意的是span不能识别到
# print(img_src)
name = response.meta["name"]
movie = ScrapyStudy05MovieItem(name=name, src=img_src)
yield movie # 将数据返回给管道
其中主要的重点就是:
对第二页url进行请求:
yield scrapy.Request(url=url, callback=self.parse_second, meta={"name": name})
六、CrawlSpider
6.1、简介
CrawlSpider 是 Scrapy 框架中的一个常用类,专门用于编写爬取网站的规则导向型爬虫。
它继承自 Scrapy 的 Spider 类,并提供了更灵活的机制来处理复杂的网站导航结构。
相对于基础的 Spider,CrawlSpider 允许你定义一系列规则(rules),通过这些规则,爬虫可以自动跟踪链接并处理页面。
所以,如果有需要跟进链接的需求,意思就是爬取了网页之后,需要提取链接再次爬取,使用crawlspider是非常合适的
6.2、链接提取器
在链接提取器里面可以写规则来提取我们想要的链接列表。
使用之前需要先导入
from scrapy.linkextractors import LinkExtractor
语法:
操作 | 含义 |
---|---|
allow =() | 正则表达式提取符合正则的链接 |
deny =() | 正则表达式不提取符合正则的链接(不常用) |
allow_domains =() | 允许的域名(不常用) |
deny_domains =() | 不允许的域名(不常用) |
restrict_xpaths =() | xpath,提取符合xpath规则的链接 |
restrict_css =() | 提取符合选择器规则的链接(不推荐) |
示例:
from scrapy.linkextractors import LinkExtractor
link = LinkExtractor(allow=r'/book/1188_\d+\.html')
link.extract_links(response)
r'/book/1188_\d+\.html'
,其中,r是忽略转义的字符。
输出所有符合正则表达式的链接:
七、CrawlSpider案例实战
需求:某读书网站数据入库
7.1、项目初始化
-
新建项目
scrapy startproject scrapy_study_06_dushu
-
创建爬虫类
cd .\scrapy_study_06_dushu\scrapy_study_06_dushu\spiders\ scrapy genspider -t crawl read https://www.dushu.com/book/1188.html
- 其中
-t
参数的意义就是会给我们多新增加一些内容,利于我们使用CrawlSpider。 - 还有follow参数:follow=true 是否跟进就是按照提取连接规则进行提取(如果是True将会一直爬取数据直至最后一页。)
- 其中
7.2、改造项目
-
爬虫文件:
import scrapy from scrapy.linkextractors import LinkExtractor from scrapy.spiders import CrawlSpider, Rule from scrapy_study_06_dushu.items import ScrapyStudy06DushuItem class ReadSpider(CrawlSpider): name = "read" allowed_domains = ["www.dushu.com"] # 原网页是1188但是不符合我们下面的正则规则,所以原网页会丢失,现在改成1188_1 start_urls = ["https://www.dushu.com/book/1188_1.html"] rules = (Rule(LinkExtractor( allow=r"/book/1188_\d+\.html"), callback="parse_item", follow=False),) def parse_item(self, response): img_list = response.xpath("//div[@class='bookslist']//img") for img in img_list: name = img.xpath("./@alt").extract_first() src = img.xpath("./@data-original").extract_first() book = ScrapyStudy06DushuItem(name=name, src=src) yield book
-
items文件
# Define here the models for your scraped items # # See documentation in: # https://docs.scrapy.org/en/latest/topics/items.html import scrapy class ScrapyStudy06DushuItem(scrapy.Item): # define the fields for your item here like: # name = scrapy.Field() name = scrapy.Field() src = scrapy.Field()
-
pipelines文件
# Define your item pipelines here # # Don't forget to add your pipeline to the ITEM_PIPELINES setting # See: https://docs.scrapy.org/en/latest/topics/item-pipeline.html # useful for handling different item types with a single interface from itemadapter import ItemAdapter class ScrapyStudy06DushuPipeline: def open_spider(self, spider): self.fp = open("dushu.json", "w", encoding="utf-8") def process_item(self, item, spider): self.fp.write(str(item)) return item def close_spider(self, spider): self.fp.close()
-
在setting.py中打开设置
7.3、运行并查看结果
八、联动mysql数据库持久化到本地
案例就是第七章的内容继续改造。
8.1、安装pymysql
使用命令在python的安装目录下
pip install pmysql
8.2、创建mysql数据库
sql语句:
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for spider01
-- ----------------------------
DROP TABLE IF EXISTS `spider01`;
CREATE TABLE `spider01` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
`src` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 521 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
不懂MySQL的安装和使用的朋友先去简单入门一下mysql,我这里就直接放上数据库的字段和sql语句。
推荐快速入门的教程:mysql的安装
8.3、编写配置
在settings.py
文件中的任意位置编写配置的参数信息:
# 数据库连接参数
DB_HOST = "localhost"
DB_PORT = 3306
DB_USER = 'root'
DB_PASSWORD = 'toor'
DB_NAME = 'spider1'
DB_CHARSET = 'utf8'
注意:必须要是与自己数据库参数对应才行。
8.4、编写数据库持久化管道类
# 加载settings数据
from scrapy.utils.project import get_project_settings
import pymysql
class MysqlPipeline:
def open_spider(self, spider):
settings = get_project_settings()
self.host = settings['DB_HOST']
self.port = settings['DB_PORT']
self.db = settings['DB_NAME']
self.user = settings['DB_USER']
self.password = settings['DB_PASSWORD']
self.charset = settings['DB_CHARSET']
self.conn = pymysql.connect(
host=self.host,
port=self.port,
db=self.db,
user=self.user,
password=self.password,
charset=self.charset)
self.cursor = self.conn.cursor()
def process_item(self, item, spider):
# 编写插入数据的sql语句
sql = 'insert into spider01(name,src) values("{}","{}")'.format(item['name'], item['src'])
# 执行sql语句
self.cursor.execute(sql)
# 提交数据
self.conn.commit()
return item
def close_spider(self, spider):
self.cursor.close()
self.conn.close()
8.5、开启管道
将数据库持久化的管道类在setting.py
配置文件中进行配置
ITEM_PIPELINES = {
"scrapy_study_06_dushu.pipelines.ScrapyStudy06DushuPipeline": 300,
"scrapy_study_06_dushu.pipelines.MysqlPipeline": 301,
}
8.6、测试并观察数据库中保存的结果
九、日志与日志文件
科普一下日志级别相关信息:
-
CRITICAL:严重错误
-
ERROR:般错误
-
WARNING:警告
-
INFO:一般信息
-
DEBUG:调试信息
默认的日志等级是DEBUG
只要出现了DEBUG或者DEBUG以上等级的日志
那么这些日志将会打印
对于scrapy的日志管理在setting.py
文件中可以进行设置
- 默认的级别为DEBUG,会显示上面所有的信息
- 在配置文件中settings·py
- LOG_FILE:将屏幕显示的信息全部记录到文件中,屏幕不再显示,注意文件后缀一定是
.log
- LOG_LEVEL:设置日志显示的等级,就是显示哪些,不显示哪些
具体配置如下:
# 指定日志的级别
LOG_LEVEL = 'INFO'
LOG_FILE = 'log.txt'
十、scrapy的post请求
具体是写start_requests
方法:def start_requests(self)
start_requests的返回值:
scrapy.FormRequest(url=url,headers=headers, callback=self.parse_item, formdata=data)
其中:
- url:要发送的post地址
- headers:可以定制头信息
- callback:回调函数
- formdata:post所携带的数据,这是一个字典
具体以百度翻译示例:
在创建项目之后,对start_requeats文件进行重新:
import scrapy
import json
class FanyiSpider(scrapy.Spider):
name = "fanyi"
allowed_domains = ["fanyi.baidu.com"]
start_urls = ["https://fanyi.baidu.com/sug"]
def start_requests(self):
url = 'https://fanyi.baidu.com/sug'
data = {
'kw': 'hello'
}
yield scrapy.FormRequest(url=url, formdata=data, callback=self.parse_second)
def parse_second(self, response):
# 解决编码问题
print(json.loads(response.text))
运行发现毫无问题。
十一、scrapy的代理
在Scrapy中使用代理可以帮助你绕过一些反爬虫机制或避免IP被封禁。可以通过以下几种方式实现Scrapy的代理设置:
11.1、 在 settings.py
中配置代理
在Scrapy的 settings.py
中可以通过设置 HTTP_PROXY
或 DOWNLOADER_MIDDLEWARES
来全局配置代理。例如:
# settings.py
HTTP_PROXY = 'http://your_proxy_ip:proxy_port'
DOWNLOADER_MIDDLEWARES = {
'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750,
'your_project.middlewares.CustomProxyMiddleware': 543,
}
HttpProxyMiddleware
是Scrapy自带的中间件,你可以通过设置 HTTP_PROXY
来为所有请求指定一个代理。
11.2、 自定义代理中间件
如果需要根据不同请求设置不同的代理,可以自定义一个代理中间件:
# middlewares.py
import random
class CustomProxyMiddleware(object):
def __init__(self):
self.proxies = [
'http://proxy1_ip:proxy1_port',
'http://proxy2_ip:proxy2_port',
'http://proxy3_ip:proxy3_port',
]
def process_request(self, request, spider):
# 随机选择一个代理
proxy = random.choice(self.proxies)
request.meta['proxy'] = proxy
spider.logger.info(f"Using proxy: {proxy}")
然后在 settings.py
中启用这个中间件:
# settings.py
DOWNLOADER_MIDDLEWARES = {
'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware': 750,
'your_project.middlewares.CustomProxyMiddleware': 543,
}
11.3、 为特定请求设置代理
如果你不想为所有请求都设置代理,可以在 spider
中为某些请求动态设置代理:
def start_requests(self):
urls = ['http://example.com', 'http://another-site.com']
for url in urls:
request = scrapy.Request(url=url, callback=self.parse)
request.meta['proxy'] = 'http://your_proxy_ip:proxy_port'
yield request
11.4、 使用第三方代理服务
如果你需要大量代理,可能需要使用一些代理池或者代理服务。可以通过API获取代理,并在 middlewares.py
中根据实际需求动态设置代理。
class DynamicProxyMiddleware(object):
def fetch_proxy(self):
# 调用API获取代理
response = requests.get('https://proxy-provider.com/api/get_proxy')
return response.text
def process_request(self, request, spider):
proxy = self.fetch_proxy()
request.meta['proxy'] = proxy
spider.logger.info(f"Using proxy: {proxy}")
通过这种方式,你可以动态地获取代理,并应用于请求。
这些方法可以灵活地帮助你在Scrapy中设置和管理代理,从而提高爬虫的成功率。