Scrapy+爬取豆瓣电影Top250信息
「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战」
Scrapy爬虫框架
scrapy是什么
它是一个快速功能强大的开源网络爬虫框架 Github地址:github.com/scrapy/scra… 官网地址:scrapy.org/
scrapy的安装
cmd上运行
pip install scrapy 测试: scrapy -h
一般直接pip install scrapy会出错,可参考:【转】
blog.csdn.net/qq_42543250…
安装成功后测试会(scrapy -h):
Scrapy爬虫框架结构
“5+2”结构
框架组件:
组件 | 作用 |
---|---|
Scrapy Engine | 引擎,处理整个框架的数据流 |
Scheduler | 调度器,接收引擎发过来的请求,将其排至队列中,当引擎再次请求时返回 |
Downloader | 下载器,下载所有引擎发送的请求,并将获取的源代码返回给引擎,之后由引擎交给爬虫处理 |
Spiders | 爬虫,接收并处理所有引擎发送过来的源代码,从中分析并提取item字段所需要的数据,并将需要跟进的url提交给引擎,再次进入调度器 |
Item Pipeline | 管道,负责处理从爬虫中获取的Item,并进行后期处理 |
Downloader Middlewares | 下载中间件,可以理解为自定义扩展下载功能的组件 |
Spider Middlewares | Spider中间件,自定义扩展和操作引擎与爬虫之间通信的功能组件 |
Scrapy爬虫的数据类型
- Request类
- Response类
- Item类
Scrapy数据处理流程:
- 当需要打开一个域名时,爬虫开始获取第一个url,并返回给引擎
- 引擎把url作为一个请求交给调度器
- 引擎再次对调度器发出请求,并接收上一次让调度器处理的请求
- 引擎将请求交给下载器
- 下载器下载完成后,作为响应返回给引擎
- 引擎把响应交给爬虫,爬虫开始进一步处理,处理完成后有两个数据,一个是需要跟进的url,另一个是获取到的item数据,然后把结果返回给引擎
- 引擎把需要跟进的url给调度器,把获取的item数据给管道
- 然后从第2步开始循环,知道获取信息完毕。只有调度器中没有任何请求时,程序才会停止
Scrapy爬虫的基本使用
yield关键字的使用
- 包含yield语句的函数是一个生成器
- 生成器每次产生一个值(yield语句),函数被冻结,被唤醒后再产生一个值
- 生成器是一个不断产生值的函数
Scrapy爬虫的常用命令
命令 | 说明 | 格式 |
---|---|---|
startproject | 创建一个新工程 | scrapy startproject projectName |
genspider | 创建一个爬虫 | scrapy genspider [options]name domain |
settings | 获得爬虫配置信息 | scrapy settings [options] |
crawl | 运行一个爬虫 | scrapy crawl spider |
list | 列出工程中所有爬虫 | scrapy list |
shell | 启动URL调试命令行 | scrapy shell [url] |
Scrapy爬虫的使用步骤
- 新建项目 (scrapy startproject xxx):新建一个新的爬虫项目
创建工程:scrapy startproject mydemo
目录树:
工程目录下各个文件的作用
文件 | 作用 |
---|---|
scrapy.cfg | 配置文件 |
spiders | 存放你Spider文件,也就是你爬取的py文件 |
items.py | 相当于一个容器,和字典较像 |
middlewares.py | 定义Downloader Middlewares(下载器中间件)和Spider Middlewares(蜘蛛中间件)的实现 |
pipelines.py | 定义Item Pipeline的实现,实现数据的清洗,储存,验证。 |
settings.py | 全局配置 |
- 明确目标 (编写items.py):明确你想要抓取的目标
items.py文件内容
- 制作爬虫 (spiders/xxspider.py):制作爬虫开始爬取网页
Spider爬虫模板:
- 存储内容 (pipelines.py):设计管道存储爬取内容
实例:豆瓣Top250信息-Scrapy爬虫
创建工程:
scrapy startproject douban 在douban目录下: scrapy genspider douban_scrapy douban.com
明确目标
我们打算抓取movie.douban.com/top250 网站里的所有电影的序号、名称、介绍、评分、评论数、描述
打开 douban 目录下的 items.py。
Item 定义结构化数据字段,用来保存爬取到的数据,有点像 Python 中的 dict,但是提供了一些额外的保护减少错误。
可以通过创建一个 scrapy.Item 类, 并且定义类型为 scrapy.Field 的类属性来定义一个 Item(可以理解成类似于 ORM 的映射关系)。
接下来,创建一个 ItcastItem 类,和构建 item 模型(model)。
items.py
import scrapy
class DoubanItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
# 电影序号
serial_number = scrapy.Field()
# 电影名称
movie_name = scrapy.Field()
# 电影介绍
introduce = scrapy.Field()
# 电影星级
star = scrapy.Field()
# 电影评论数
evaluate = scrapy.Field()
# 电影描述
describe = scrapy.Field()
制作爬虫 (spiders/douban_scrapy.py)
在当前目录下输入命令,将在mySpider/spider目录下创建一个名为itcast的爬虫,并指定爬取域的范围:
scrapy genspider douban_scrapy movie.douban.com
打开 douban/spider目录里的 douban_scrapy.py,默认增加了下列代码:
#douban_scrapy.py
#-*- coding: utf-8 -*-
import scrapy
from douban.items import DoubanItem
class DoubanScrapySpider(scrapy.Spider):
name = 'douban_scrapy'
allowed_domains = ['movie.douban.com']
start_urls = ['https://movie.douban.com/top250']
def parse(self, response): # 解析的方法
# movie_list 的类型为<class 'scrapy.selector.unified.SelectorList'>
movie_list = response.xpath("//ol[@class ='grid_view']/li")
# 数据的查找
# self.log('movie_list 的类型为{}
for i_item in movie_list:
# item文件的导入
douban_item = DoubanItem()
# 数据的筛选
#extract():这个方法返回的是一个数组list,,里面包含了多个string,如果只有一个string,则返回['ABC']这样的形式。
#extract_first():这个方法返回的是一个string字符串,是list数组里面的第一个字符串。
douban_item['serial_number'] = i_item.xpath(".//div[@class='pic']/em/text()").extract_first()
douban_item['movie_name'] = i_item.xpath(".//div[@class='hd']/a/span[1]/text()").extract_first()
douban_item['introduce'] = i_item.xpath(".")
content = i_item.xpath(".//div[@class='bd']/p[1]/text()").extract()
for i_content in content:
contents = "".join(i_content.split())
douban_item['introduce'] = contents
douban_item['star'] = i_item.xpath(".//div[@class='star']/span[2]/text()").extract_first()
douban_item['evaluate'] = i_item.xpath(".//div[@class='star']/span[4]/text()").extract_first()
douban_item['describe'] = i_item.xpath(".//p[@class= 'quote']/span/text()").extract_first()
#将数据返回到pipeline,用生成器
yield douban_item
next_link = response.xpath("//span[@class ='next']/link/@href").extract()
# 解析下一页,规则,取后一页的xpath
if next_link:
next_link = next_link[0]
#Spider产生下一页的Request请求
yield scrapy.Request('https://movie.douban.com/top250'+next_link,callback=self.parse)
保存数据 (pipeline.py)
一.scrapy保存信息的最简单的方法主要有四种,-o 输出指定格式的文件,命令如下:
scrapy crawl douban_scrapy -o douban.json
json lines格式,默认为Unicode编码
scrapy crawl douban_scrapy -o douban.jsonl
csv 逗号表达式,可用Excel打开
scrapy crawl douban_scrapy -o douban.csv
xml格式
scrapy crawl douban_scrapy -o douban.xml
二、通过pipeline存储进mysql
pipeline.py
import pymysql
from twisted.enterprise import adbapi
from scrapy import log
class DoubanPipeline(object):
#使用teisted异步存储
def __init__(self, dbpool):
self.dbpool = dbpool
@classmethod
def from_settings(cls, settings):
dbparms = {
'host': "localhost",
'user': "root",
'port': 3306,
'passwd': "root",
'db': "mystudy",
'charset': 'utf8',
'cursorclass': pymysql.cursors.DictCursor,
'use_unicode': True
}
dbpool = adbapi.ConnectionPool('pymysql', **dbparms)
return cls(dbpool)
def process_item(self, item, spider):
# 使用Twisted 将MYSQL 插入变成异步执行
# runInteraction 第一个参数是一个函数
query = self.dbpool.runInteraction(self.do_insert, item)
query.addCallback(self.handle_error, item, spider) # 处理异常
return item
def handle_error(self, failure, item, spider):
# 处理异步插入的异常
print(failure)
def do_insert(self, cursor, item):
# 执行具体的插入
insert_sql = '''
insert into douban (serial_number,movie_name,introduce,star, evaluate,Mdescribe) values (%s, %s, %s, %s, %s, %s);
'''
cursor.execute(insert_sql,
(item['serial_number'], item['movie_name'], item['introduce'], item['star'], item['evaluate'],item['describe']))
一些配置
#settings.py
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
ROBOTSTXT_OBEY = False
ITEM_PIPELINES = {
'douban.pipelines.DoubanPipeline':10
}
转载自:https://juejin.cn/post/7026225595511996429