一、背景环境
- 环境介绍
操作系统:Win10
Python版本:Python3.6
Scrapy版本:Scrapy1.5.1
二、创建项目
- 一般的流程
新建项目 (scrapy startproject xxx):新建一个新的爬虫项目
明确目标 (编写items.py):明确你想要抓取的目标内容
制作爬虫 (spiders/xxspider.py):制作爬虫开始爬取网页
存储内容 (pipelines.py):设计管道存储爬取内容
配置文件(settings.py):配置你的爬虫
- 创建工程
> scrapy startproject dingdian[projectname]
- 创建爬虫
> cd dingdian
> scrapy genspider dd https://www.23us.so/list/1_1.html(dd 为爬虫名称,https://www.23us.so/list/1_1.html是要爬取的url)
- 目录结构
scrapy.cfg:项目的配置信息,主要为Scrapy命令行工具提供一个基础的配置信息。(真正爬虫相关的配置信息在settings.py文件中)
items.py:设置数据存储模板,用于结构化数据,如:可以理解为Django的Model(但不会生成对应的表和字段)
pipelines:数据处理行为,如:一般结构化的数据持久化
settings.py:配置文件,如:递归的层数、并发数,延迟下载等
spiders:爬虫文件目录,如:里面存放着你的爬虫文件,在此编写你的爬虫规则
middlewares:中间件(钩子),可以理解成Django的中间件(钩子)
三、编写爬虫
-
明确目标(编写items.py)
Item 定义结构化数据字段,用来保存爬取到的数据,有点像Python中的dict,但是提供了一些额外的保护减少错误。scrapy.Field的类属性来定义一个Item(可以理解成类似于ORM的映射关系)。
这里我们通过一个继承自scrapy.Spider的爬虫来进行演示
# items.py文件
import scrapy
# 书籍信息
class DingdianItem(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
book_name = scrapy.Field()
book_auth = scrapy.Field()
new_chapter = scrapy.Field()
......
# 书籍内容
class ContentItem(scrapy.Item):
p_name = scrapy.Field()
chapter_title = scrapy.Field()
......
- 制作爬虫(spiders/xxxx.py)
制作爬虫的过程中我们可以使用Scrapy的shell工具来进行我们代码的调试。
# spiders/dd_xs.py文件
import scrapy
from dingdian.items import DingdianItem
class DdXsSpider(scrapy.Spider):
name = 'dd' # 爬虫名称, 必须唯一
allowed_domains = ['www.23us.so'] #爬虫的约束区域, 只允许爬取该域名下的网站内容
start_urls = ['https://www.23us.so/'] # 开始爬虫的列表
# 对start_urls中的url返回的网页数据进行解析或处理
def parse(self, response):
# 实例化我们items.py里面的DingdianItem
item = DingdianItem()
# 用xpath选择器进行匹配, 也可以用css选择器。返回的都是选择器对象。所以我们用extract_first():只匹配第一个文本数据进行测试。
# 提取书名内容
book_name = response.xpath('//*[@id="content"]//tr[@bgcolor="#FFFFFF"]//td[@class="L"][1]/a/text()').extract_first()
# 提取最新章节
new_chapter = response.xpath('//*[@id="content"]//tr[@bgcolor="#FFFFFF"]//td[@class="L"][2]/a/text()').extract_first()
# 提取作者
book_auth = response.xpath('//*[@id="content"]//tr[@bgcolor="#FFFFFF"]//td[@class="C"][1]/text()').extract_first()
# 存入到我们的Item
item['book_name'] = book_name
item['book_auth'] = book_auth[i]
item['book_size'] = book_size[i]
#将获取的数据交给pipelines,由pipelines来进行持久化存储或者去重、过滤、等其他处理
yield item
要建立一个Spider, 你必须用scrapy.Spider类创建一个子类,并确定了三个强制的属性 和 一个方法。
- name = "xxx" :这个爬虫的识别名称,必须是唯一的,在不同的爬虫必须定义不同的名字
- allow_domains = [] 是搜索的域名范围,也就是爬虫的约束区域,规定爬虫只爬取这个域名下的网页,不存在的URL会被忽略。
- start_urls =[]:爬取的URL元祖/列表。爬虫从这里开始抓取数据,所以,第一次下载的数据将会从这些urls开始。其他子URL将会从这些起始URL中继承性生成。
- parse(self, response)方法 :解析的方法,每个初始URL完成下载后将被调用,调用的时候传入从每一个URL传回的Response对象来作为唯一参数
parse方法主要作用:负责解析返回的网页数据(response.body),提取结构化数据(生成item)生成需要下一页的URL请求。将start_urls的值修改为需要爬取的第一个url。
- pipelines持久化存储
我们将获取到的内容保存到MySQL数据库中, 一般来说数据库的配置或者sql语句我们都可以放到其它的文件当中为了方便管理。但是在这里为了方便我就直接在pipelines文件中书写了。
# pipelines.py文件
import pymysql
from dingdian.items import DingdianItem
class DingdianPipeline(object):
def process_item(self, item, spider):
# 连接数据库
my_sql = pymysql.connect(host='localhost', port=3306, user='root', password='123456', charset='utf8', db='erms_xs', use_unicode=True)
# 获取游标
cur = my_sql .cursor()
try:
# 插入书籍信息到erms_book_info
if isinstance(item, DingdianItem):
cur.execute("insert into erms_book_info( book_name, book_auth, book_size) VALUES (%s, %s, %s)", (item['book_name'], item['book_auth'], item['book_size'])
# 提交
my_sql .commit()
# 关闭游标
cur.close()
# 关闭数据库连接
my_sql.close()
except Exception as e:
my_sql .commit()
cur.close()
my_sql .close()
print("出现异常:", e)
finally:
return item
items文件并不会自动的帮我们在数据库创建对应的数据库和表结构, 所以我们需要在数据库中建立对应的数据库和表结构在进行pipeline持久化存储。
这里是我从之前的某个DEMO里面拷贝出来的一部分, 所以有些地方看起来感觉比较奇怪。
- 开启pipelines
# settings.py文件
ITEM_PIPELINES = {
# 300代表优先级,值越低优先级越高
'dingdian.pipelines.DingdianPipeline': 300,
}
四、 执行爬虫
- 执行
scrapy crawl dd(爬虫名称)
# Scrapy中有Medie Pipeline 可以帮助我们下载图片和文件
scrapy crawl dd -o test.json json文件
scrapy crawl itcast -o teachers.jsonl json lines格式
scrapy crawl dd -o test.csv csv文件
scrapy crawl dd -o 'ftp://USER:[email protected]/test.json' FTP文件服务器