先附上源代码的github 链接:传送门
手写了那么多次爬虫,多多少少都会发现,很多代码都在重用,有代码经常性的在重复使用,说明,这些代码肯定有框架可以直接实现,Scrapy就是写爬虫最常用的一个框架,本着学习与娱乐结合的意愿,咱就用这个框架去爬一下最经典的豆瓣top250的电影吧。
当然,本文是参照了博客:传送门 来写的,这是一个经典的爬虫案例,所以,大致代码,大家都差不多。
好了,废话不多说。直接开干。
首先我们先看看:
红线标记的地方,就是本次我们需要爬取的内容:
包括:电影标题,电影信息,电影评分,电影金句(哈哈,就当这么说吧~)
对框架有啥不理解的,详细可以看这个:传送门
以本文为例,首先得先安装scrapy ,直接命令行:
pip3 install scrapy
安装好之后,先创建一个Scrapy项目,进入您打算存储代码的目录中,运行下列命令:
scrapy startproject Douban
你就会发现目录下是这个样子的:
当然,其中的mydouban.py , movie.xlsx, 以及main.py,你刚创建的时候是没有的,这是我的项目创建的,先忽略,后面会说。
那么这些文件分别是:
- scrapy.cfg: 项目的配置文件
- Douban/: 该项目的 python 模块。之后您将在此加入代码。
- Douban/items.py: 项目中的 item 文件。
- Douban/pipelines.py: 项目中的 pipelines 文件。
- Douban/settings.py: 项目的设置文件。
- Douban/spiders/: 放置 spider 代码的目录。
好了,这个时候,整个项目架构是有了,那么我们先开始第一步:定义Item
最上面,已经说了本文爬虫需要爬的东西是啥,那么我们为此定义一下对应的Item
当你按照上述流程创建好项目之后,打开items.py,你能看到一个DoubanItem的类,当然,最开始里面啥也没有,
我们需要“电影标题,电影信息,电影评分,电影金句”,那么分别为这四个内容根据scrapy的规定,创建变量用来保存资源。
title = scrapy.Field()
movie_info = scrapy.Field()
score = scrapy.Field()
quote = scrapy.Field()
Item 创建好了,这回得开始创建爬虫了,在spider的目录下创建我们的第一个爬虫:mydouban.py
Spider 是用户编写用于从单个网站(或者一些网站)爬取数据的类。
其包含了一个用于下载的初始 URL,如何跟进网页中的链接以及如何分析页面中的内容, 提取生成 item
的方法。
为了创建一个 Spider,您必须继承 scrapy.Spider
类, 且定义以下三个属性:
name
: 用于区别 Spider。 该名字必须是唯一的,您不可以为不同的 Spider 设定相同的名字。start_urls
: 包含了 Spider 在启动时进行爬取的 url 列表。 因此,第一个被获取到的页面将是其中之一。 后续的 URL 则从初始的 URL 获取到的数据中提取。parse()
是 spider 的一个方法。 被调用时,每个初始 URL 完成下载后生成的Response
对象将会作为唯一的参数传递给该函数。 该方法负责解析返回的数据(response data),提取数据(生成 item)以及生成需要进一步处理的 URL 的 `Request 对象。
# -*- coding:utf-8 -*-
"""
Created on 2019/6/22
@author:Ray Li
"""
import scrapy
from Douban import items
class MyDouban(scrapy.Spider):
name = "Douban"
start_urls = ["https://movie.douban.com/top250"]
url = "https://movie.douban.com/top250"
def parse(self, response):
item = items.DoubanItem()
movies = response.xpath('//div[@class="info"]')
for movie in movies:
title = movie.xpath('div[@class="hd"]/a/span[@class="title"]/text()').extract()
# print(title)
full_title = ''
for each in title:
full_title += each
movie_info = movie.xpath('div[@class="bd"]/p/text()').extract()[0]
score = movie.xpath('div[@class="bd"]/div[@class="star"]/span[@class="rating_num"]/text()').extract()[0]
quote = movie.xpath('div[@class="bd"]/p[@class="quote"]/span/text()').extract()[0]
# print("######################################")
# print(movie_info)
# print(score)
# print(quote)
# print(title)
# print("######################################")
item['title'] = full_title
item['movie_info'] = movie_info
item['quote'] = quote
item['score'] = score
yield item
nextPage = response.xpath('//span[@class="next"]/a/@href').extract()
if nextPage:
nextPage = nextPage[0]
yield scrapy.Request(self.url + nextPage, callback=self.parse)
看到这么一大串,先别怕,根据描述一步步来:
首先我们创建了一个spider类 :MyDouban,继承了scrapy.Spider
根据上文提到的三个属性,name,URL,parse
那么最开始,我们得定义一个爬虫的名字,和爬虫要爬取的初始URL集合吧~
然后就要创建一个parse函数不~
这样大致的框架已经出来,具体,我们得关注parse 内的函数该怎么写。
我们先看一下要爬取的网页结构:
是不是发现,我们要爬取的内容在一个class属性为“info”的div中?,所以啊,第一个代码:
movies = response.xpath('//div[@class="info"]')
利用xpath 去获取网页中所有的,class属性为“info”的div,那么关于xpath 不会的话 ,请参照W3C文档:传送门
那么后续的获取“title”,“score”什么的就都差不多了。
东西拿到手之后,我们得存在之前我们创建的Item里啊,所以:
item['title'] = full_title
item['movie_info'] = movie_info
item['quote'] = quote
item['score'] = score
yield item
最后把item对象返回。
好了这个时候,其实我们的爬虫就快完成了,第一页的内容我们就都爬取出来了,
如果你就爬一页,那么这个爬虫到“yield item” 就已经结束了,
但是250个电影肯定一页放不下啊,所以我们在爬完一页之后(for循环结束后),得获取到下一次爬取的链接,
也就是下一页的链接。
nextPage = response.xpath('//span[@class="next"]/a/@href').extract()
if nextPage:
nextPage = nextPage[0]
yield scrapy.Request(self.url + nextPage, callback=self.parse)
利用回调操作,下一次,他又会将新的URL 调回parse去爬取(当然,固定格式就是这样)。
oK ,我们这回终于完成了爬虫,但是,还忽略了一个问题,你好歹也伪装一下爬虫吧,还有你也没把数据给存下来啊。
伪装好办,不是有个setting.py文件嘛,打开之后,去看里面的注释,把USER_AGENT的注释给去掉,改成你的浏览器USER_AGENT,这样就能假装我们是通过浏览器访问的啦。
USER_AGENT = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36'
为了保存数据,我们就要编辑pipelines.py了,他里面可以将传进来的Item做自定义的一些操作。
当 Item 在 Spider 中被收集之后,它将会被传递到 Item Pipeline,一些组件会按照一定的顺序执行对 Item 的处理。
每个 item pipeline 组件(有时称之为“Item Pipeline”)是实现了简单方法的 Python 类。他们接收到 Item 并通过它执行一些行为,同时也决定此 Item 是否继续通过 pipeline,或是被丢弃而不再进行处理。
以下是 item pipeline 的一些典型应用:
- 清理 HTML 数据
- 验证爬取的数据(检查 item 包含某些字段)
- 查重(并丢弃)
- 将爬取结果保存到数据库中
编写你自己的 item pipeline 很简单,每个 item pipeline 组件是一个独立的 Python 类,同时必须实现以下方法:
process_item(self, item, spider)
每个 item pipeline 组件都需要调用该方法,这个方法必须返回一个 Item (或任何继承类)对象, 或是抛出 DropItem 异常,被丢弃的 item 将不会被之后的 pipeline 组件所处理。
那么好办,数据都已经保存在Item里了,那么我们,就把Item里的数据写到EXCEL 文件中去把:
# -*- 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 openpyxl
class DoubanPipeline(object):
def __init__(self):
self.wb = openpyxl.Workbook()
self.sheet = self.wb.create_sheet('电影TOP250')
self.sheet.append(['电影标题', '电影信息', '电影评分', '电影金句'])
def process_item(self, item, spider):
print(type(item['score']))
line = [item['title'], item['movie_info'].strip(), item['score'], item['quote']]
self.sheet.append(line)
self.wb.save("movie.xlsx")
return item
按照流程创建好的项目里,打开pipelines.py,可以看到DoubanPipeline 这个类,里面有一个没有函数体的process_item函数,然后自己在里面对Item 内容进行处理就好了,对了,编辑好pipelines.py后,为了启用一个 Item Pipeline 组件,你必须将它的类添加到 ITEM_PIPELINES 配置
ITEM_PIPELINES = {
'Douban.pipelines.DoubanPipeline': 300,
}
后面的300 是优先级哈,分配给每个类的整型值,确定了他们运行的顺序,item 按数字从低到高的顺序,通过 pipeline,通常将这些数字定义在 0-1000 范围内。
最后呢,你可以通过命令行的方式去执行:
scrapy crawl Douban
这样就能启动爬虫,然后等爬虫结束就能拿到自己的资源了。
当然,先麻烦的话,可以自己创建一个main.py:
# -*- coding:utf-8 -*-
"""
Created on 2019/6/22
@author:Ray Li
"""
from scrapy import cmdline
cmdline.execute('scrapy crawl Douban'.split())
这样就可以在pycharm里面直接运行了!
那么,本文到这就结束啦,哈哈,很简单把~!
最后附上,爬虫获取的电影资源截图: