上回我们说到,如何使用python的requests请求库爬取豆瓣高分电影榜,本次就说一说如何使用scrapy这个python爬虫框架去实现爬虫功能。
首先,使用scrapy的框架需要经历一下步骤:
- 创建一个scrapy工程。
- 编写spider。
- 编写item。
- 编写pipelines
上述的四个步骤就完成了一个网站从请求、下载、解析网页、保存的过程。接下也会按照这四个步骤去编写代码。
创建工程项目
scrapy的工程创建在命令行中完成的。首先在命令行中输入,就可以创建一个名字叫做cnblogSpider项目。
scrapy startproject cnblogSpidr
创建好项目后,我们的项目文件结构如下:
cnblogSpidr/
crapy.cfg
cnblogSpidr/
__init__.py
items.py
middlewares.py
pipelines.py
settings.py
spiders/
__init__.py
这些文件的作用分别如下:
scrapy.cfg:项目部署文件
cnblogSpider/:该项目的python模块,之后可以再次加入代码。
cnblogSpider/items.py:项目中的Item文件。
cnblogSpider/popelines.py:项目中的Pipelines文件
cnblogSpider/setting.py:项目配置文件。
cnblogSpider/spider/:放置Spider代码的目录。
以上就完成了第一步,也就是scrapy项目的创建。按照爬取流程,我们需要建立一个请求,在requests中直接是使用get()方法就行了,而在scrapy中我们需要做的就是编写一个spider.py文件。在上述的项目spider目录下创建一个名称为cnblog_Spider.py的文件,在这个文件中编写代码。代码如下:
import scrapy
import json
import sys
sys.path.append(".")
from cnblogSpider import items
class DbSpider(scrapy.Spider):
name="dbspider"
# allowed_domains=["douban.com"]
# start_urls=["https://movie.douban.com/j/search_subjects?type=movie&tag=%E8%B1%86%E7%93%A3%E9%AB%98%E5%88%86&sort=rank&page_limit=20&page_start=0"]
def start_requests(self):
header={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0'}
url="https://movie.douban.com/j/search_subjects?type=movie&tag=%E8%B1%86%E7%93%A3%E9%AB%98%E5%88%86&sort=rank&page_limit=20&page_start=0"
return [scrapy.Request(url,callback=self.parse)]
def parse(self,response):
pass
我们会导入一些相关的库,最重要的是scrapy,因为我们需要继承一个scrapy.Spider类,对网站发起的请求都会通过这个继承这个类来完成。
class DbSpider(scrapy.Spider):#继承Spider类
这个scrapy.Spider类有一些重要的属性和方法,
name:是项目的名字,必须唯一。
allowed_domains:是允许爬取的域名,比如一些网站有相关链接,域名就和本网站不同,这些就会忽略。
start_urls:是Spider爬取的网站,定义初始的请求url,可以多个。第一个被获取到的页面的URL将是其中之一,后续的URL则从初始的URL的响应中主动提取。
parse()方法:用于处理在请求start_url后,之后的方法,这个方法是获取每个初始URL响应后返回的Respone对象,将作为唯一参数传给该方法。对网页的解析,与提取(生成item)以及生成需要进一步处理的URL的Request对象。
start_request:该方法返回一个可迭代对象,该对象包好了spider用于爬取的第一个request。
上述代码中parse方法留空了,而且没有用到allowed_domains,和start_urls这两个属性。是因为我在这里重写了staet_request方法。这样可以自定义request请求相关的数据,如请求头之类的,也可以定制User-Agent参数用于反爬虫(创建UA池用于反爬虫的方法在文章末)。当然,如果不适用start_request重写也可以,示例如下:
import scrapy
class CnblogsSpider(scrapy.Spider):
name='cnblogs'#爬虫的名称
allowed_domains=['cnblogs.com']#允许的域名
start_urls=['http://www.cnblogs.com/qiyeboy/default.html?page=1']
def parse(self,reponse):
#实现网页的解析
pass
我们在start_request中重写,目的是为了将自定义一些和请求有关的请求头。在请求头中添加User-Agent的方式如下。
def start_requests(self):
header={'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko/20100101 Firefox/73.0'}
url="https://movie.douban.com/j/search_subjects?type=movie&tag=%E8%B1%86%E7%93%A3%E9%AB%98%E5%88%86&sort=rank&page_limit=20&page_start=0"
return [scrapy.Request(url,headers=header,callback=self.parse)]
以上一个包含请求头的start_request方法就创建好了,该方法只执行一次,对给定的url发起请求,并返回一个响应。而我们请求的文件是一个json文件。在parse中就不会用太多的方式去解析。有关scrapy的解析方式此链接(官方文档)
现在需要的做的事是编写item。这在文件目录的cnblogSpider下的items.py文件。这个文件的作用是创建用于保存数据的字段。
import scrapy
class CnblogspiderItem(scrapy.Item):
movie_url=scrapy.Field()
title=scrapy.Field()
rate=scrapy.Field()
其中的title=scrapy.Field()就是创建了一个字段为title。因为只爬取了豆瓣电影title,url,rate三种数据,所以这里就创建这三种字段。
创建好item后,就可以在cnblog_Spider.py中调用了,接下来编写parse(),用于解析数据和保存数据。需要注意的是,items.pycnblog_Spider.py的上层目录,如果想要调用它,就得添加路径如下:
import scrapy
import json
import sys
sys.path.append(".")#添加上层目录的路径
from cnblogSpider import items
def parse(self,response):
j=json.loads(response.body)['subjects']
for i in j:
title=i['title']
rate=i['rate']
movie_url=i['url']
item=items.CnblogspiderItem(title=title,movie_url=movie_url,rate=rate)
yield item
从response中提取到title,rate,url等数据。如何添加到刚才建立的item中呢?
item=items.CnblogspiderItem(title=title,movie_url=movie_url,rate=rate)
这样就将title,movie_url,rate等数据通过参数的方法创建了一个item对象,最后用yield返回。那么数据就能保存到item对应的字段中了。
接下来,在将数据保存到item字段后,需要做的就是将这些数据输出到数据库或者本地。与之相关的文件是popelines.py。打开该文件输入以下代码:
import json
from scrapy.exceptions import DropItem#用于测试异常
class CnblogspiderPipeline(object):
def __init__(self):
self.file=open('douban.json','w')
def process_item(self, item, spider):
if item['title']:
line=json.dumps(dict(item))
self.file.write(line)
return item
else:
raise DropItem('Missing title in %s'% item)
return item
这就是将数据保存到文件douban.json的文件中了。但是创建了pipelines后还需要将其激活,不然不能使用。在settings.py文件中建立一个ITEM_PIPELINES字段,将刚才的pipelines写进入去,如下,最后的300可以理解为优先级的意思,scrapy中可以使用0-1000。
ITEM_PIPELINES = {
# 'scrapy.pipelines.images.ImagesPipeline': 1,
'cnblogSpider.pipelines.CnblogspiderPipeline': 300
}
以上就完成了所有的一个完整的scrapy项目的代码编写。还差最后一步运行爬虫。在终端中输入下列代码:
scrapy crawl dbspider
dbspider就是在cnblog_Spider.py中的name属性。如果运行没错就会在cnblog_Spider文件夹下生成一个douban.json的文件。最好的学习scrapy的方式就是去啃官方文档
之前使用的UA是硬编码进去的,如何建立一个UA池,并在request时随机的从这个UA池挑选一个user-agent呢?请听下次分解。
网友评论