前几天学习了scrapy的框架结构和基本的使用方法,部分内容转载自:http://blog.csdn.net/qq_30242609/article/details/52810840
scrapy由编写蜘蛛的spiders文件夹和其他框架自带的几个python文件组成
其中
items.py
双击打开这个文件,看一下都初始化了什么东西
# -*- coding: urf-8 -*-
# Define here the models for your scrapyed items
#
# See documentation in
# http://doc.scrapy.org/en/latest/topics/items.html
import scrapy
class HeartsongItem(scrapy.Item):
# define the fields for your item here like:
#
# name = scrapy.Filed()
pass
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
通过里面的注释可见,这个文件的作用是定义我们要爬取信息的标准格式,打个比方说,如果我们要爬取一批人的个人信息,包括姓名,性别,生日,那么我们可以这样来书写这个文件
import scrapy
class HeartsongItem(scrapy.Item):
name = scrapy.Filed()
sex = scrapy.Filed()
birthday = scrapy.Filed()
- 1
- 2
- 3
- 4
- 5
- 6
易见本文件只是定义了一个类,至于什么时候实例化它,怎么保存它,请继续了解下面的内容。
settings.py
如其名,这是本项目的配置文件,里面注释着很多常用的配置项,我们通过在其他文件中引入本文件的方式来使用这些配置项。
当然,我们可以把这些注释都删掉,等需要开启哪个功能的时候再另行编辑。
我们此处先看看默认打开的配置项吧
BOT_NAME = 'heartsong'
SPIDER_MODULES = ['heartsong.spiders']
NEWSPIDER_MODULE = 'heartsong.spider'
# Obey robots.txt rules
ROBORSTXT_OBEY = True
- 1
- 2
- 3
- 4
- 5
因为我们写的是定向爬虫,前面三个按默认即可,我们不去管他。看第四项,注释里说这个配置项的意思是是否遵守robots.txt
,那么robots.txt
是个什么东西呢?
通俗来说,robots.txt
是遵循Robot协议的一个文件,它保存在网站的服务器中,它的作用是,告诉搜索引擎爬虫,本网站哪些目录下的网页不希望你进行爬取收录。在Scrapy启动后,会在第一时间访问网站的robots.txt
文件,然后决定该网站的爬取范围。
当然,我们并不是在做搜索引擎,而且在某些情况下我们想要获取的内容恰恰是被robots.txt
所禁止访问的。所以,我们就将此配置项设置为False
,拒绝遵守Robot协议!
pipelines.py
双击打开这个文件,看看都初始化了什么东西
# -*- coding: utf-8 -*-
# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
class HeartsongPipeline(object):
def process_item(self, item, spider):
return item
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
从注释中所能得到的信息微乎其微,只告诉我们要启用此文件的话必须要在settings.py
里配置一下ITEM_PIPELINES
,好,那我们就老老实实的去settings.py
里配置一下吧,不过注意,此处有坑,在1.0.x版本(极客学院教程中使用),配置项用list格式来书写,而在最新的1.1.2版本中,需要用dict格式,否则会报错,无法爬取,配置好后,我们的setting.py
如下:
# -*- coding: utf-8 -*-
BOT_NAME = 'heartsong'
SPIDER_MODULES = ['heartsong.spiders']
NEWSPIDER_MODULE = 'heartsong.spider'
ROBORSTXT_OBEY = True
ITEM_PIPELINES = {
'heartsong.pipelines.HeartsongPipeline': 300,
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
此处的300表示优先级,因为本项目只用到这一个pipeline,所以随意取0-1000中的一个数值即可。
好,镜头切回pipelines.py
,这个文件到底有什么用呢?当然用处很多啦,本教程中介绍的作用只有两个:
* 对爬取到的数据(Item)进行处理,比如存入数据库
* 爬虫结束时产生事件,比如发送一封邮件
爬虫
在默认生成的spiders
目录下新建heartsong_spider.py
,我们的爬虫就写在这里面,因为是介绍,那么此处就写个简单的下载网站的主页,让大家能运行一下,感受一下scrapy。
import scrapy
class HeartsongSpider(scrapy.spiders.Spider):
name = "heartsong" # 爬虫的名字,执行时使用
allowed_domains = ["heartsong.top"] # 允许爬取的域名,非此域名的网页不会爬取
start_urls = [
"http://www.heartsong.top" # 起始url,此例只爬这一个页面
]
def parse(self, response): # 真正的爬虫方法
html = response.body # response是获取到的来自网站的返回
# 以下四行将html存入文件
filename = "index.html"
file = open(filename, "w")
file.write(html)
file.close()
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
要说明的是,这个类不是随心所欲来写的,name
,allowed_domains
,start_urls
,都是类似于”重载”的值。也就是说,scrapy内部会检测这些变量的值,变量名不可以起成其它的名字,类似的变量之后还会有介绍。至于parse
方法,就是重载的父类的方法,我们爬虫的主体一般就写在这里面。
好,现在让我们来运行它
在命令行中进入heartsong目录下,执行命令
scrapy crawl heartsong
- 1
此处的名字heartsong是与爬虫类中的name
保持一致。
以上是scrapy的基本架构。
由于递归爬取的时候存在超链接指向图片等问题反而增加request工作量,目前主要思考通过首先爬取所有up主信息,再爬取其空间内视频信息的办法。但是具体的爬取方案无法确定。如果要采取不遗漏的方法,又只能从视频方面开始爬取,回到了最初的问题。目前error视频的数量大概占总数量的一半,问题还不是很大,暂时搁置递归爬取的问题。
目前依然采取根据av号枚举的方式访问视频并记录信息。根据测试程序的反馈,scrapy的爬取效率并不比request的方法高多少。。。可能有部分人认为的效率高主要由于scrapy自带的多进程爬取的方法。但是当request也采取多进程爬取时,主要耗时依然在于获取网络源码的过程中。这部分的时间目前没有办法减少。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import scrapy
import re
class bilibili(scrapy.Spider):
name = "bilibili"
# 允许的域名
allowed_domains = ["bilibili.com"]
start_urls = []
for av in xrange(10000):
start_urls.append("http://www.bilibili.com/video/av"+str(av))
def parse(self, response):
page = response.body
temp = re.search(r'<div class="v-title"><h1 title="(.+?)">', page)
if temp:
title = re.search(r'<div class="v-title"><h1 title="(.+?)">', page).group(1)
authorkit = re.search(r'r-info.+?title="(.+?)"', page)
if authorkit:
author = authorkit.group(1)
aid = re.search(r'aid=(\d+)', page).group(1)
cid = re.search(r'cid=(\d+)', page).group(1)
print cid
print aid
url = 'https://api.bilibili.com/x/web-interface/archive/stat?aid='+str(aid)
return scrapy.http.Request(url=url, callback=self.parse_item_page)
def parse_item_page(self, response):
print response.body