
前言
最近非常热衷于看电影,准备做一个电影方面的数据分析,所以这次爬虫项目练习就做一次猫眼电影吧。
因为本篇文章是接上篇Scrapy框架的安装及入门,结合官方文档进行编写。所以会着大量篇幅在介绍框架的用法以及详细解释。
猫眼电影页面很多,这次练习抓取最简单的榜单页面。
Get Started
创建项目
scrapy startproject maoyan
可爬取的数据
- 标题
- 主演
- 上映时间
- 海报地址
- 评分
创建数据模型Item
import scrapy
class MaoyanItem(scrapy.Item):
# define the fields for your item here like:
title = scrapy.Field() #标题
stars = scrapy.Field() # 主演
showtime = scrapy.Field() # 上映时间
img = scrapy.Field() # 图片地址
score = scrapy.Field() # 评分
看到这里唯一有疑惑的地方就是这个Field
对象了。由于Field
对象支持所有类型的值,所以无需像数据库那样为数据类型操心了。简单来说Item
类的用法相当于是一个字典,它可以与Dictionary
对象相互转换。
开始着手Spider文件
在spiders中创建maoyanSpider.py
并定义初始化属性
import scrapy
class TestProject(scrapy.Spider):
name = 'maoyan'
allow_domains = ['maoyan.com']
start_urls = ['https://maoyan.com/board/7']
def parse(self, response):
self.log(response.url)
-
name
:定义spider名字的字符串,一个项目中可以有多个spider。比如一个项目中我可以爬取猫眼的榜单或者评论,可以通过name
属性来区分开。 -
allow_domains
: 包含了spider允许爬取的域名列表。 当OffsiteMiddleware
(会在后面说明)启用时, 域名不在列表中的URL不会被跟进。 -
start_urls
: 如果没有指定特定的URL,Spider会从start_urls
中的URL获取数据。
Scrapy提取数据
Scrapy框架支持xpath
和css3
两种选择器。
import scrapy
class TestProject(scrapy.Spider):
name = 'maoyan'
allow_domains = ['maoyan.com']
start_urls = ['https://maoyan.com/board/7']
def parse(self, response):
movies = response.xpath('//dl[@class="board-wrapper"]//dd')
item = MaoyanItem()
for movie in movies:
item['title'] = movie.css('p.name a::text').extract_first()
item['stars'] = movie.css('p.star::text').extract_first().strip()
item['showtime'] = movie.css('p.releasetime::text').extract_first().strip()
item['score'] = movie.css('i.integer::text').extract_first() + movie.css('i.fraction::text').extract_first()
item['img'] = movie.css('a.image-link img.board-img::attr(data-src)').extract_first()
yield item
以上就是爬取数据的部分,其实非常简单。个人比较喜欢用css3来解析,因为他写法比较简洁易读。而且有时候在用xpath的时候会遇到解析不了的情况。
对选择器不熟悉的可以参考以下几篇文章恶补下:
CSS选择器与xpath
爬虫解析库Xpath
CSS3选择器
反爬虫与反反爬虫
由于爬虫的盛行,很多网站都实行了反爬虫策略。这次在爬取猫眼电影的时候也遇到了这种情况。所谓知己知彼,百战不殆,要想克服这道关卡首先得了解反爬虫是什么。
关于反爬虫的知识可以参考这篇文章,里面写的还是很详细而且通俗易懂,强烈推荐:
关于反爬虫看这一篇就够了
通常反爬虫有那么几种基础手段:
- 封ip 如果一个ip在某时间段内的请求超过阈值就会被认定为爬虫
- 检测useragent 发现某个用户在某段时间内请求量超过阈值会被认定为爬虫
针对这两种可以用代理ip以及模拟useragent来达到反反爬虫的目的。我们可以自己搭建代理ip池和useragent池,为了节省时间我选择使用fake-useragent
和proxy_pool
库,以后有空了再研究。
安装fake-useragent以及 proxy_pool
& pip install fake-useragent
& git clone git@github.com:jhao104/proxy_pool.git
# 进入proxy_pool目录后
& pip install -r requirements.txt
具体环境配置以及安装查看链接,这里不再说明了
Spider的中间件 ---- Middleware
Spider中间件是介入到Scrapy的spider处理机制的钩子框架,您可以添加代码来处理发送给 Spiders的response及spider产生的item和request。
如果想要修改ip以及useragent,必须涉及到request
新建manager文件夹并创建ProxyPoolManager.py
封装proxy_pool
的接口
数据库个人使用的是redis,所以端口和官方demo会不一样。
import requests
class ProxyPoolManager(object):
"""docstring for ProxyPoolManager"""
def get_proxy():
return requests.get("http://127.0.0.1:6379/get/").json()
def delete_proxy(proxy):
requests.get("http://127.0.0.1:6379/delete/?proxy={}".format(proxy))
下一步编辑middleware文件
from scrapy import signals
from testproject.manager.proxypoolManager import ProxyPoolManager
from fake_useragent import UserAgent
# 创建自定义中间件
class RandomUserAgentMiddlware(object):
def __init__(self,crawler):
super(RandomUserAgentMiddlware,self).__init__()
self.ua = UserAgent() # 初始化UserAgent
@classmethod
def from_crawler(cls,crawler):
return cls(crawler)
def process_request(self, request, spider):
request.headers.setdefault("User-Agent",self.ua.random) # 为requests设置useragent
retry_count = 5
proxy = ProxyPoolManager.get_proxy().get("proxy") # 从代理池中取出ip地址
while retry_count > 0:
try:
request.meta['proxy'] = proxy
# 使用代理访问
except Exception:
retry_count -= 1
# 出错5次, 删除代理池中代理
delete_proxy(proxy)
**因为使用了自定义中间件,所以必须要在settings.py
中声名并且安排优先级
DOWNLOADER_MIDDLEWARES = {
'testproject.middlewares.RandomUserAgentMiddlware': 333
}
跑下程序测试下
在终端输入
scrapy crawl maoyan
最后结果,成功抓取到数据了

数据存储和导出
Scrapy提供了非常方便的导出方案,支持csv,json,xml等格式。
以本项目为例:
- 直接导出
& scrapy crawl maoyan -o maoyan.csv
去当前目录中查看下:

小结
在这个项目中当我们了解了Scrapy框架中每个文件的作用之后,其实会感觉到爬虫项目没有想象当中那么难。遇到反爬虫也不要慌乱,先去了解反爬虫的策略后很容易就能想到针对方案。(其实一开始对反爬虫我也碰壁了~)
爬虫实战这块还没完,等有空会做一个更大一点的项目,这个练习的数据量太少了。当然对于反爬虫也会逐步深入进去。
网友评论