前言
利用scrapy爬取豆瓣上top250条电影信息其实挺容易的,主要是用来熟悉一下如何利用scrapy快速写一个爬虫。
开始启动一个scrapy项目
进入到想要创建scrapy项目的目录下
scrapy startproject douban_top_250
当我们想要写一个爬虫的时候后要知道我们想要从哪爬取,想要爬取什么,爬取下来的数据我们需要进行什么样的处理。
设计需要爬取的item
先打开豆瓣电影top250这个页面。
可以看到这个页面展示了电影的名字、排名、导演、演员等信息。当我们点击每一个链接时还会有更多的信息:
例如《肖申克的救赎》,这个详情页面展示了评分评论数还有用户给出的评论等信息。
所以,我们可以爬取下这部电影的名称、导演、编剧、主演、类型、制片国家、语言、上映时间、片长、别名、排名、评分,评论人数等信息。
import scrapy
#items.py
#这个文件
class Douban_Top_250Item(scrapy.Item):
# define the fields for your item here like:
# name = scrapy.Field()
chinese_name = scrapy.Field()
english_name = scrapy.Field()
director = scrapy.Field()
screenwriter = scrapy.Field()
main_actors = scrapy.Field()
type = scrapy.Field()
district = scrapy.Field()
show_date = scrapy.Field()
duration = scrapy.Field()
other_name = scrapy.Field()
score = scrapy.Field()
rank = scrapy.Field()
language = scrapy.Field()
count_conmment = scrapy.Field()
开始着手Spider
from scrapy import Spider
from scrapy.http import Request
class crawlDoubanMovie(Spider):
name = "douban_top_250"
#因为豆瓣屏蔽了scrapy默认的header。
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',
}
def start_requests(self):
url = 'https://movie.douban.com/top250'
yield Request(url, headers=self.headers)
def parse(self,response):
#后面单独来写。
pass
}
这样实现了一个能访问豆瓣电影top250的超简单爬虫。
parse函数是scrapy中用来对url进行处理的默认函数,也可以在Request中加入新的callback函数。
#在crawlDoubanMovie前面有4个indent。暂时省略了
def parse(self, response):
#将每部电影的URL传入到一个专门的函数中进行数据提取,也可以直接在parse函数中进行处理
post_urls = response.xpath('//ol[@class="grid_view"]/li//div[@class="hd"]/a/@href').extract()
for post_url in post_urls:
yield Request(url =parse.urljoin(response.url,post_url),callback=self.parse_detail,headers=self.headers)
使用了XPath对节点进行了选择
在对页面中每一个电影的链接进行请求后,这个页面的有用信息基本上就爬取完成,还剩下一个很重要的操作,就是对下一页的链接进行请求然后进行爬取。通过查看页面,发现可以对“后页”这个链接进行请求
最后一页时后页无链接
也可以对下面的“1,2,3,4....”链接进行获取,不过这样只能针对页数很少的网站。
def parse(self,response):
...
next_url = response.xpath('//*[@id="content"]/div/div[1]/div[2]/span[3]/a/@href').extract_first()
yield Request(parse.urljoin(response.url,next_url),headers=self.headers)
自定义一个parse_detail函数,对电影详情页面的数据进行处理。
#我使用了ItemLoader,也可以不使用loader直接将值通过键值对的形式传给Item.py
from scrapy.loader import ItemLoader
def parse_detail(self,response):
text_xpath="//*[@id='info']/text()"
text = [element.strip() for element in response.xpath(text_xpath).extract()]
while "" in text:
text.remove("")
while "/" in text:
text.remove("/")
print(text)
movieItemLoader = ItemLoader(item=Douban_Top_250Item(),response=response)
movieItemLoader.add_xpath("chinese_name","//*[@id='content']/h1/span[1]/text()")
movieItemLoader.add_xpath("english_name","//h1/span[1]/text()")
movieItemLoader.add_xpath("director","//*[@id='info']/span[1]/span[@class='attrs']/a/text()")
movieItemLoader.add_xpath("screenwriter","//*[@id='info']/span[2]/span[@class='attrs']/a/text()")
movieItemLoader.add_xpath("main_actors",'//*[@id="info"]/span[3]/span[@class="attrs"]/a/text()')
movieItemLoader.add_xpath("type",'//*[@id="info"]/span[@property="v:genre"]/text()')
movieItemLoader.add_value("district",text[0])
movieItemLoader.add_value("language",text[1])
movieItemLoader.add_value("other_name",text[2])
movieItemLoader.add_xpath("show_date",'//*[@id="info"]/span[@property="v:initialReleaseDate"]/text()')
movieItemLoader.add_xpath("duration",'*[@id="info"]/span[@property="v:runtime"]/text()')
movieItemLoader.add_xpath("rank",'//*[@id="content"]/div[1]/span[1]/text()')
movieItemLoader.add_xpath("count_comment","//span[@property=v:votes]/text()")
movieItemLoader.add_xpath("score",'//span[@property="v:average"]/text()')
movieItem = movieItemLoader.load_item()
yield movieItem
上面代码中的text是为了处理
纯文本这样的纯文本,它存在于父节点的文本中,所以要进行处理才能提取到。(个人感觉是豆瓣很懒。。。写的很难看)
关于ItemLoader
ItemLoader中将所有爬取到的信息都设置为list,所以要设置好ItemLoader的output_processors。通过查看ItemLoader的源码
可以看到,我们可以改变default_output_processor
那么我们在item中进行写一个自己的ItemLoader
#items.py
from scrapy.loader.processors import TakeFirst
class MovieItemLoader(ItemLoader):
default_output_processor = TakeFirst
这样就可以将返回的item中取出list中的第一个元素。可是有的数据本身就是一个list,我们可以通过一个方法,将默认的输出给覆盖掉。
def return_value(value):
return value
value即是itemloader所传入的值
既然要使用自己写的ItemLoader,就需要在spider中修改使用的默认ItemLoader
from ..items import MovieItemLoader
...
movieItemLoader = MovieItemLoader(item=Douban_Top_250Item(),response=response
...
)
剩下的即是在items中写一些方法将itemloader传入的value进行input_processor和output_processor的处理。使用的大概方法即是在scrapy.Filed()中添加方法,可以使用MapCompose将多个方法组合在
一起。
例如:
screenwriter = scrapy.Field(
input_processor=方法,
output_processor=方法
)
最后
最后肯定要将采集好的数据进行存储。可以使用两种方式:一种是使用scrapy自带的feed export,另一种是自己写pipeline将数据保存为自己想要的格式,例如存入到数据库,保存为CSV,保存为json等。
以后接着写,to be continued
最后的最后
今天晚上九寨沟发生了7级地震,希望同胞安好
网友评论