功能:
爬取豆瓣电影Top 250的电影信息(序号、电影名、介绍、星级、评论数、描述)。
运行环境:
Windows10 + Anaconda + Pycharm
参考:
https://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/tutorial.html#id4
https://www.imooc.com/video/17516
目录
一、创建项目
1.1 搭建环境
1 使用Anaconda配置好虚拟环境,包括依赖的安装。
Python3.6
scrapy
requests
urllib3
lxml
libxml2
cssselect
parsel
w3lib
Twisted
安装方式:
Anaconda Prompt 常用命令
1 打开Anaconda Prompt
2 创建虚拟环境:conda create -n 环境名称 python=3.6
3 激活虚拟环境:conda activate 环境名称
4 安装库:pip install 名称 -i https://pypi.tuna.tsinghua.edu.cn/simple(使用镜像,下载更快)
安装scrapy时,会自动安装前置库。
2 打开PyCharm建立项目,并将刚刚建立的虚拟环境作为该项目编译器。
1.2 创建项目文件
打开PyCharm的Terminal界面,输入scrapy startproject 项目名
,建立scrapy项目。
如: scrapy startproject douban
成功后获得如下项目目录:
scrapy.cfg: 项目的配置文件
douban/: 该项目的python模块。之后您将在此加入代码。
douban/items.py: 项目中的item文件.
douban/pipelines.py: 项目中的pipelines文件.
douban/settings.py: 项目的设置文件.
douban/spiders/: 放置spider代码的目录.
1.3 创建爬虫文件
打开terminal界面,输入:
cd douban
scrapy genspider douban_spider movie.douban.com
创建名为douban_spider.py
的文件爬取movie.douban.com
网站。
1.4 定义Item
Item 是保存爬取到的数据的容器;其使用方法和python字典类似, 并且提供了额外保护机制来避免拼写错误导致的未定义字段错误。
首先根据需要从unsplash.com获取到的数据对item进行建模。 我们需要从unsplash中获取名字,url,以及网站的描述。 对此,在item中定义相应的字段。
import scrapy
class ImgCrawlerItem(scrapy.Item):
# define the fields for your item here like:
name = scrapy.Field()
pass
1.5 编写Spider
Spider是用户编写用于从单个网站(或者一些网站)爬取数据的类。
其包含了一个用于下载的初始URL,如何跟进网页中的链接以及如何分析页面中的内容, 提取生成 item 的方法。
import scrapy
class ImgSpider(scrapy.Spider):
name = 'ImgSpider' # 用于区别Spider,该名字必须是唯一的,不可以为不同的Spider设定相同的名字。
allowed_domains = ['unsplash.com']
start_urls = ['https://unsplash.com/'] # 包含了Spider在启动时进行爬取的url列表。
def parse(self, response): # spider的一个方法
"""
每个初始URL完成下载后生成的 Response 对象将会作为唯一的参数传递给该函数。
该方法负责解析返回的数据(response data),提取数据(生成item)以及生成需要进一步处理的URL的 Request 对象。
"""
spider暂时不包含任何内容。
1.6 运行函数main
在Terminal内运行十分麻烦,所以创建一个main函数用于启动程序。
代码如下:
from scrapy import cmdline
cmdline.execute('scrapy crawl ImgSpider'.split())
二、编辑项目
2.1 items.py 编写
想要获取网页中的以下内容:序号、电影名、介绍、星级、评论数、描述。
编写items.py
import scrapy
class DoubanItem(scrapy.Item):
serial_number = scrapy.Field() # 序号
movie_name = scrapy.Field() # 电影名
introduction = scrapy.Field() # 介绍
rating_num = scrapy.Field() # 星级
comment_num = scrapy.Field() # 评论数
quote = scrapy.Field() # 描述
2.2 xpath定位
关于Xpath:https://www.jianshu.com/p/85a3004b5c06
首先为谷歌浏览器安装扩展程序:XPath
后面将使用XPath扩展程序定位要寻找的内容。
右键点击电影名——检查,即可定位到电影的位置。
该位置为<div class="article">
\<ol class="grid_view">
\<li>
(共有25个,因为一页含有25个电影信息)
通过XPath进行定位,输入//div[@class="article"]//ol[@class="grid_view"]/li
,可以看到,共找到25个结果,说明XPath输入的内容正确。
接下来通过XPath分别定位(XPath的写法不唯一):
- serial_number序号
- movie_name电影名
- introduction介绍
- rating_num星级
- comment_num评论数
- quote描述
在//div[@class="article"]//ol[@class="grid_view"]/li
基础上分别为:
div[@class="item"]//em/text()
div[@class="info"]//div[@class="hd"]//span[@class="title"][1]//text()
div[@class="info"]//div[@class="bd"]//p[1]//text()
div[@class="info"]//div[@class="bd"]//span[@class="rating_num"]//text()
div[@class="info"]//div[@class="bd"]//div[@class="star"]//span[4]//text()
div[@class="info"]//div[@class="bd"]//p[@class="quote"]//span//text()
获取当前页面信息后,需要进行翻页,所以需要定位“后页”。
通过XPath进行定位,输入//span[@class="next"]//link//@href
,可以获得一个结果?start=25&filter=
,说明XPath输入的内容正确。
2.3 douban_spider.py编写
根据上面的规则修改douban_spider代码:
import scrapy
from items import DoubanItem
class DoubanSpiderSpider(scrapy.Spider):
name = 'douban_spider' # 爬虫名,该名字必须是唯一的,不可以为不同的Spider设定相同的名字。
allowed_domains = ['movie.douban.com'] # 允许的域名,在这个域名内进行爬取
start_urls = ['http://movie.douban.com/top250'] # 入口域名,扔到调度器中,包含了Spider在启动时进行爬取的url列表。
# 默认解析方法
def parse(self, response):
# print(response.text)
# 循环电影条数
movie_list = response.xpath('//div[@class="article"]//ol[@class="grid_view"]//li')
for i_item in movie_list:
# 创建DoubanItem类,写详细的XPath并进行数据解析
douban_item = DoubanItem()
# 获取序号
douban_item['serial_number'] = i_item.xpath(
'.//div[@class="item"]//em/text()').extract_first() # 解析第一个数据
# 获取电影名
douban_item['movie_name'] = i_item.xpath(
'.//div[@class="info"]//div[@class="hd"]//span[@class="title"][1]//text()').extract_first()
# 获取介绍
content = i_item.xpath(
'.//div[@class="info"]//div[@class="bd"]//p[1]//text()').extract()
for i_content in content:
content_s = "".join(i_content.split())
douban_item['introduction'] = content_s
# 获取星级
douban_item['rating_num'] = i_item.xpath(
'.//div[@class="info"]//div[@class="bd"]//span[@class="rating_num"]//text()').extract_first()
# 获取评论数
douban_item['comment_num'] = i_item.xpath(
'.//div[@class="info"]//div[@class="bd"]//div[@class="star"]//span[4]//text()').extract_first()
# 获取描述
douban_item['quote'] = i_item.xpath(
'.//div[@class="info"]//div[@class="bd"]//p[@class="quote"]//span//text()').extract_first()
# print(douban_item)
# 将数据yield到piplines里面
yield douban_item # 进入到pipelines
# 解析下一页规则,取后页的XPath
next_link = response.xpath('//span[@class="next"]//link//@href').extract()
if next_link: # 判断是否到最后一页
next_link = next_link[0]
yield scrapy.Request("http://movie.douban.com/top250"+next_link, callback=self.parse)
运行main.py,获取相应的信息:
2.4 数据保存
2.4.1 json格式
首先需要在pipelines.py
内定义保存格式:
import json
class JsonPipeline:
def __init__(self):
self.file = open('top250.json', 'wb')
def process_item(self, item, spider):
line = json.dumps(dict(item), ensure_ascii=False) + "\n" # ensure_ascii=False 中文不乱码
print(line)
self.file.write(line.encode('utf-8'))
return item
再修改settings.py
文件,找到ITEM_PIPELINES
选项:
ITEM_PIPELINES = {
'douban.pipelines.JsonPipeline': 300
}
运行main.py
记可得到top250.json
:
2.4.2 xls文件
首先需要在pipelines.py
内定义保存格式:
import xlwt
class CsvPipeline:
def __init__(self):
self.book = xlwt.Workbook(encoding='utf-8')
self.sheet = self.book.add_sheet('top250')
self.sheet.write(0, 0, 'serial_number')
self.sheet.write(0, 1, 'movie_name')
self.sheet.write(0, 2, 'introduction')
self.sheet.write(0, 3, 'rating_num')
self.sheet.write(0, 4, 'comment_num')
self.sheet.write(0, 5, 'quote')
self.row = 1
def process_item(self, item, spider):
self.sheet.write(self.row, 0, item['serial_number'])
self.sheet.write(self.row, 1, item['movie_name'])
self.sheet.write(self.row, 2, item['introduction'])
self.sheet.write(self.row, 3, item['rating_num'])
self.sheet.write(self.row, 4, item['comment_num'])
self.sheet.write(self.row, 5, item['quote'])
self.row += 1
self.close_file(item)
def close_file(self, item):
self.book.save('top250.xls')
return item
再修改settings.py
文件,找到ITEM_PIPELINES
选项:
ITEM_PIPELINES = {
'douban.pipelines.CsvPipeline': 300
}
运行main.py
记可得到top250.xls
: