Scrapy简介
Scrapy 是一个用于爬取和提取数据的开源web抓取框架。它提供了一个强大的机制,让开发者可以轻松地创建和管理爬虫程序,以从网站上自动提取结构化的数据。
以下是Scrapy的一些主要特点和优势:
- 强大灵活的爬取能力:Scrapy具有高度可配置的请求处理和数据提取功能。它可以轻松地处理包括JavaScript渲染页面、登录验证、代理设置等在内的复杂爬取场景。
- 高效的异步处理:Scrapy采用异步非阻塞的方式进行网络请求和数据处理,能够高效地处理大规模的请求和并发。
- 分布式支持:Scrapy可以通过分布式的方式进行爬取,让多个爬虫实例同时工作,提高爬取效率。
- 内置的数据提取工具:Scrapy提供了强大的选择器(Selector)和XPath等工具,用于方便地从页面中提取结构化的数据。
- 中间件和拓展性:Scrapy的中间件机制使得对请求和响应进行自定义处理变得简单。它还提供了丰富的拓展接口,方便开发者根据自己的需求进行扩展和定制。
- 内置的调试工具:Scrapy提供了方便的日志记录和调试工具,帮助开发者定位和解决爬取中的问题。
- 文档丰富,活跃的社区支持:Scrapy拥有完善的文档和活跃的社区支持,您可以轻松地找到大量的教程、示例和解答问题的资源。
总之,Scrapy是一个功能强大、灵活可配置的Web抓取框架,适用于各种规模的爬取任务。它可以帮助开发者高效地构建和管理爬虫,提取所需的数据,并支持大规模的并发和分布式爬取。
Scrapy使用流程
- 创建爬虫项目.
scrapy startproject xxx
- 进入项目目录.
cd xxx
- 创建爬虫
scrapy genspider 名称 抓取域
- 编写
item.py
文件, 定义好数据item - 修改spider中的parse方法. 对返回的响应response对象进行解析. 返回item
- 在pipeline中对数据进行保存工作.
- 修改
settings.py
文件, 将pipeline设置为生效, 并设置好优先级 - 启动爬虫
scrapy crawl 名称
- 引擎(engine)
scrapy的核心, 所有模块的衔接, 数据流程梳理. - 调度器(scheduler)
本质上这东西可以看成是一个集合和队列. 里面存放着一堆我们即将要发送的请求. 可以看成是一个url的容器. 它决定了下一步要去爬取哪一个url. 通常我们在这里可以对url进行去重操作. - 下载器(downloader)
它的本质就是用来发动请求的一个模块. 小白们完全可以把它理解成是一个requests.get()的功能. 只不过这货返回的是一个response对象. - 爬虫(spider)
这是我们要写的第一个部分的内容, 负责解析下载器返回的response对象.从中提取到我们需要的数据. - 管道(pipeline)
这是我们要写的第二个部分的内容, 主要负责数据的存储和各种持久化操作.
Scrapy使用
pip install scrapy
建议安装最新版
创建Scrapy项目
scrapy startproject 项目名称
创建爬虫
cd 文件夹 # 进入项目所在文件夹
scrapy genspider 爬虫名称 允许抓取的域名范围
├── mySpider_2
│ ├── __init__.py
│ ├── items.py
│ ├── middlewares.py
│ ├── pipelines.py
│ ├── settings.py
│ └── spiders
│ ├── __init__.py
│ └── youxi.py # 多了一个这个.
└── scrapy.cfg
编写Spider
class XiaoyouxiSpider(scrapy.Spider):
name = 'xiaoyouxi'
allowed_domains = ['4399.com'] # 当前爬虫允许爬取的域名 白名单
# 只要不符合以上域名,scrapy自动屏蔽
start_urls = ['http://www.4399.com/flash/'] # 起始URL
def parse(self, response): # 默认的解析位置,主要负责第一个url的解析工作
li_games = response.xpath("//ul[@class='n-game cf']/li")
for game in li_games:
name = game.xpath("./a/b/text()").extract_first() # 游戏名
fenlei = game.xpath("./em/a/text()").extract_first() # 游戏分类
shijian = game.xpath("./em/text()").extract_first() # 游戏上线时间
# print(name, fenlei, shijian)
"""
使用的是scrapy的xpath,拿到的是selectorlist
extract_first()提取第一个
extract()提取全部
"""
youxi_dict = {
"name": name,
"fenlei": fenlei,
"shijian": shijian
}
# 爬虫必须返回请求对象、item(数据,字典充当一条数据)、none(空)
yield youxi_dict
# 生成器 可以返回数据 而不打断函数的执行
# return返回时 函数停止
编写pipelines
存储数据
#管道想要开启,必须在setting中开启
class Youxi4399Pipeline:
def process_item(self, item, spider):
print(item)
with open("data.csv",mode="a",encoding="UTF-8") as f:
f.write(f"{item['name']},{item['fenlei']},{item['shijian']}\n")
return item
修改setting
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36'
ROBOTSTXT_OBEY = False #是否遵守robots协议
LOG_LEVEL ="WARNING" #增加日志级别,只有警告及以上才会打印在控制台
DOWNLOAD_DELAY = 1 #访问延迟,类似time.sleep(),协程失效
ITEM_PIPELINES = {
'youxi4399.pipelines.Youxi4399Pipeline': 300, #300 优先级
数据展示
自定义数据传输结构item
在上述案例中, 我们使用字典作为数据传递的载体, 但是如果数据量非常大. 由于字典的key是随意创建的. 极易出现问题, 此时再用字典就不合适了. Scrapy中提供item作为数据格式的声明位置. 我们可以在items.py文件提前定义好该爬虫在进行数据传输时的数据格式. 然后再写代码的时候就有了数据名称的依据了.
item.py文件
import scrapy
class GameItem(scrapy.Item):
# 定义数据结构
name = scrapy.Field()
category = scrapy.Field()
date = scrapy.Field()
class Person:
private String name;
private int age;
dic = {name: "alex", age: 18}
p = Person( "alex", 18)
spider中可以这样使用
from mySpider_2.items import GameItem
# 以下代码在spider中的parse替换掉原来的字典
item = GameItem()
item["name"] = name
item["category"] = category
item["date"] = date
yield item
快捷执行Scrapy代码
Scrapy目录下新建py文件
from scrapy.cmdline import execute
if __name__ == '__main__':
execute("..\\..\\..\\venv\\Scripts\\scrapy.exe crawl xiaoyouxi".split())