Scrapy大名鼎鼎,看到某网站mv不错,手动下载太麻烦,于是用scrapy来实现抓取。
基本思路是研究网站的首页、电影的列表页面、及其播放页面,获取页面中格式化的信息,页面到页面的跳转关系,最终获取下载的链接。
Scrapy的架构知识,请看Scrapy架构原理介绍或是官方文档sscrapy架构介绍, 下面逐步来制作。
一、开始建立项目,写程序
scrapy提供命令行工具创建项目,在 CMD 命令行执行以下命令创建项目以及爬虫文件:
# 创建项目
1) scrapy startproject projectname
# 进入项目
2) cd projectname
# 创建爬虫文件,Scrapy 框架已经自动生成一些代码
3)scrapy genspider spidername www.xxx.com
二、修改代码,关键是spider
1)打开爬虫文件 spidername.py ,scrapy默认调用parse方法,这是处理逻辑的入口函数,首先解析首页的链接,获取电影分类的地址,然后跳转到列表页面,注意用yield scrapy.Request(url=url, callback=self.parseListPage )请求下一个页面,callback为返回后的解析方法回调
class MovieSpider(scrapy.Spider):
name = 'movie'
allowed_domains = ['xxx.com']
start_urls = ['https://xxx.com']
def parse(self, response):
#result = response.xpath('/html/body/title/text()').extract_first() /html/body/div/div/div/ul/li/div/div/
result = response.xpath('//div[@class="item-menu"]/a/@href').extract() #ul/li/div/div/div[@class="item-menu"]/a
#print('-' * 60 )
#print( result )
#print('-' * 60)
for url in result:
url = self.fullUrl( url )
yield scrapy.Request(url=url, callback=self.parseListPage )
2)解析列表页面,代码如下,核心就是xpath运用,和字符串的处理,最后获取电影播放地址并请求。
这里注意,解析的数据生成item对象,见 items.py文件,方便数据通过pipeline处理或存储。用yield data,pipeline就能接收到此对象并处理。
def parseListPage(self, response ):
#解析列表,获得mv信息和url
result = response.xpath(
'//div[@id="list_videos_common_videos_list_items"]/div[@class="item"]')
print('-' * 60)
print(len( result ))
print('-' * 60)
#pageUrl = response.url
#mvs = []
for e in result:
data = Mv05Item()
#print( e.xpath('./a[0]/@href').extract_first() )
# data-rt="1:2c8d63ec93028cf593fa06c9ab7db742:0:164936:1:"
data["id"] = e.xpath('./a/@data-rt').extract_first().split(":")[3]
data["url"] = e.xpath('./a/@href').extract_first()
data["channel"] = getChannelFromURL(response.url)
yield data
yield scrapy.Request(url=self.fullUrl( data["url"] ), callback=self.parsePlayPage )
3)解析电影播放页面,获取电影文件的地址。代码不列了
4)验证代码逻辑是否正确,我下载了3个典型页面,写测试程序验证通过。
三、修改配置文件
settings 文件的配置项,非常重要,提供了重要功能的配置参数,及扩展点的配置
#设置爬取深度,超过此值将不继续深度执行
DEPTH_LIMIT=3
# 设置user-agent,应对反爬虫是必须的选项
USER_AGENT = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:2.0.1) Gecko/20100101 Firefox/4.0.1'
#是否遵守robot协议
ROBOTSTXT_OBEY = False
DEFAULT_REQUEST_HEADERS = {
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'Accept-Language': 'en',
}
# 启用后,当从相同的网站获取数据时,Scrapy将会等待一个随机的值,延迟时间为0.5到1.5之间的一个随机值乘以DOWNLOAD_DELAY
RANDOMIZE_DOWNLOAD_DELAY=True
#对单个网站进行并发请求的最大值,默认为8
#CONCURRENT_REQUESTS_PER_DOMAIN = 16
#对单个IP进行并发请求的最大值,如果非0,则忽略CONCURRENT_REQUESTS_PER_DOMAIN设定,使用该IP限制设定。
#CONCURRENT_REQUESTS_PER_IP = 16
关于自动限速(AutoThrottle extension)的几个参数
AUTOTHROTTLE_ENABLED
True:启用;False:不启用(默认值);
AUTOTHROTTLE_START_DELAY
每一个爬虫的初始download delay,单位是秒,默认值为5.0
AUTOTHROTTLE_MAX_DELAY
允许的最大download delay,单位是秒,以防出现latency过高而导致download delay跟着变高的情况。默认值是60.0
AUTOTHROTTLE_TARGET_CONCURRENCY
针对每个网站的平均并发请求量,默认值是1.0。这是一个平均值,意味着某一时刻的并发量可能高于也可能低于这个值。
AUTOTHROTTLE_DEBUG
调试模式,日志将会打印每次响应消耗的时长latency与当前所设置的当前的Download_delay时长。这样就可以实时观察Download_delay参数的调整过程。True:开启调试;False:关闭调试(默认值)
CONCURRENT_REQUESTS_PER_DOMAIN
单个域名并发数
CONCURRENT_REQUESTS_PER_IP
单个IP并发数量
DOWNLOAD_DELAY
对同一website发起请求的间隔,默认值为0
RANDOMIZE_DOWNLOAD_DELAY
True:启动随机请求间隔,为0.5*DOWNLOAD_DELAY 至 1.5*DOWNLOAD_DELAY之间的的随机数;False:不启动;默认是True,但是因为DOWNLOAD_DELAY的默认值为0,所以要想真正启动还需要设置DOWNLOAD_DELAY
四、编写pipline,将数据存入sqlite数据库,pipeline提供了open_spider、process_item、close_spider等方法,具体用法参见pipeline项目管道用法
# 存入sqlite数据库的管道
class Mv05SQLitePipeline(object):
#开始
def open_spider(self, spider):
# 爬虫项目启动,执行连接数据操作
# 以下常量需要定义在settings配置文件中
self.db = sqlite3.connect( SQLITE_FILE )
self.cursor = self.db.cursor()
if not self.checkExist():
self.initTable()
# 向表中插入数据
def process_item(self, item, spider):
ins = 'insert into movieinfo (id, name, url, durat, rating, channel) values(?,?,?,?,?,?)'
L = [
item['id'], item['name'], item['url'], item['durat'], item['rating'], item['channel']
]
# self.cursor.execute("BEGIN TRANSACTION")
self.cursor.execute(ins, L)
self.db.commit()
return item
# 结束存放数据,在项目最后一步执行
def close_spider(self, spider):
# close_spider()函数只在所有数据抓取完毕后执行一次,
self.cursor.close()
self.db.close()
print('执行了close_spider方法,项目已经关闭')
五、运行项目
可以在命令行执行scrapy命令运行
scrapy crawl spidername
为了省去终端敲命令的环节,可以在项目中自定义一个运行文件 mian.py(注意:该文件与 scrapy.cfg 同目录),并编写如下代码:
from scrapy import cmdline
# 注意,cmdline.execute()是为了减少输入命令的操作,该方法的参数必须为列表。
# 执行爬虫文件来启动项目
cmdline.execute('scrapy crawl spidername'.split())
六、遇到的问题
1、提示KeyError: 'Spider not found,解决办法是 执行此命令时scrapy crawl spidername,spidername和spider类定义的name值要一致。
class MovieSpider(scrapy.Spider):
name = 'movie'
allowed_domains = ['xxx.com']
start_urls = ['https://xxx.com']
2、pipeline 不执行,原因是setting配置文件中没有配置自定义的pipline,配置如下即可。
#激活pipeline,否则不起作用; 多pipeline从底传递到高值
ITEM_PIPELINES = {
# 'mv05.pipelines.Mv05Pipeline': 100,
'mv05.pipelines.Mv05SQLitePipeline': 300,
}
3、需要具备xpath的知识,相关知识参见python xpath语法 或者scrapy的xpath 选择器指导
七、源代码
源代码上传github,感兴趣请访问python-space/mv06 at main · jahson88/python-space · GitHub
或者从我的资源下载爬虫程序
整体参考Python Scrapy爬虫框架实战应用 此文章。