实战爬虫还是框架来的快,最近学习了下scrapy爬虫框架,总体感觉跟django一样也是一种“重型”框架,基本啥都有,填空就行,生产力也就没话说。。。
环境搭建啥的就不赘述了,网上一大把。下面主要结合实战(爬取顶点小说网)分模块进行学习。
步骤如下:
1.创建工程目录 scrapy startproject Dingdian(跟django是不是一模一样。。。)
进一步,可以直接创建一个初始网页的爬虫:scrapy genspider dingdian http://www.23us.so/
需要注意的是,此时的dingdian是爬虫的name,在整个项目中是唯一的,而前面创建项目的Dingdian只是个文件目录名。
2.写items.py: 首先根据爬取数据的需求,定义数据字段,一般为了将网页解析后获取的数据进行格式化,可以将数据封装成一个Item类,然后对类进行操作。
使用Item类时直接继承scrapy的Item类即可。scrapy只提供Field()一种字段类型,可以用来存储任意类型的数据。
3.写爬虫最主要的部分,若先前创建了初始网页的爬虫,spider文件夹就已经有了对应的.py文件(即diangdian.py);否则,就得手动创建(文件名随意,最好跟name一致)。
spider文件完成爬虫的主要工作,包括url的构造、requests的发出、response的操作即回调函数的编写,一般还有响应数据的解析并返回给item
(一般使用yield返回,scrapy会根据settings的文件中的配置来传输到对应的pipeline类中。)
其中包括html网页解析的几种方法:css选择器+xpath语法+re+bs4,前两个直接用,repython自带,bs4是第三方库
4.写pipeline.py文件,与此同时,需要在settings.py中的ITEM_PIPELINES项进行配置。
在pipeline模块中可以实现将数据存储成json数据或者保存到mysql等数据库中。如果是图片的话,可以用scrapy自带的ImagesPipeline保存图片。
其中,将文本数据存储成Json数据时,可以自定义Pipeline类(json.dump)实现,也可以使用scrapy提供的exporter存储Json数据。
scrapy提供了一个JsonItemExporter类来进行Json数据的存储。需要注意的是,使用exporter生产的json数据被放在了一个列表里面。
官方文档学习:
1.command line tool
主要有三个功能:可以创建新的工程项目(startproject)、创建一个新的爬虫(genspider)、启动爬虫项目(crawl),
也可以通过一些特殊命令行实现特殊的功能,如:
scrapy fetch <url> 使用scrapy的downloader下载文件并输出到standard output上;
scrapy parse <url> [options] ,具体例子如 scrapy parse http://www.example.com/ -c parse_item 使用特定的回调函数对对应url返回的response进行解析。
2. Spiders
Spiders是一些定义了如何爬取一系列网页的类,包括如何完成爬取操作(如follow links)和如何从response的html页面中获取结构化数据(如scraping item)。
第一步:默认情况下,start_requests()方法中需要实现向特定的URLS(由start_urls列表指出)发出Request同时其回调函数为parse()方法(默认情况)。
第二步:在回调函数中(默认为def parse()中),实现对response的解析操作,返回结构化数据的字典或Item对象或Request对象或者这些对象的一个迭代器。
第三部:在回调函数中,实现对网页内容的提取,可以使用任意你喜欢的工具,如Xpath,正则,bs等。
第四步:最后,一般情况下会将spider返回的items持久化在一个数据库中(通过Item Pipeline)或者写入到文件中(通过Feed exports)。
任何编写的spider类都必须继承自scrapy.Spider类:
这是scrapy默认捆绑的一个类,也是最最基本的spider类,其余任何自己写的类都得继承它。它不提供任何特定的功能,
只提供一个默认的start_requests()组件(通过start_urls属性发送请求+对每个返回响应调用parse()方法进行解析)。
属性:
name 一个字符串,定义该spider的名称,it must be unique.
allowed_domains 一个字符串列表,包含了该spider被允许爬取的domains。即不在该列表域名及其子域名包含范围内的urls的requests是不被接受的。
当然该属性可以通过设置项OffsiteMiddleware更改。
start_urls 一个url的列表,列出了没指出特定的urls时该spider开始爬取的地址。该列表只是定义了“首地址”,后续爬取的urls是由解析的html中重新构造。
custom_settings 一个用于自定义属性的字典。不常用。
crawler 该属性通过初始化类from_crawler()设置,它将Crawler对象链接到该spider的实例被限制的对象。。(翻译的自己都看不懂了 尴尬。。。用到了再细看吧)
settings 运行此spider时的配置。
logger 用spider的name创建的python logger。可以通过它发送日志消息。
方法:
from_crawler(crawler,*args,**kwargs) 该方法是Scrapy用于创建该spider时的类方法,默认配置就像是对__int__()方法的一个代理,一般不用重写此方法。
start_requests() 该方法必须返回一个包含第一个爬取操作的Request的迭代器。当scrapy开始工作时,该方法就会被首先调用,但只会被调用一次!
如果需要更改这种默认设置,如第一步不是爬取主页而是使用一个POST request 进行登录操作,则:
class MySpider(scrapy.Spider):
name = 'myspider'
def start_requests(self):
return [scrapy.FormRequest("http://www.example.com/login",
formdata={'user': 'john', 'pass': 'secret'},
callback=self.logged_in)]
def logged_in(self, response):
# here you would extract links to follow and return Requests for
# each of them, with another callback
pass
parse(self, response) 该方法是scrapy中默认处理downloaded responses的回调函数。该方法(其他回调函数也一样)负责处理response,返回爬取的数据或者follow的urls。
该方法或者说是任意回调函数,都必须返回一个Request的迭代器或者包含数据的字典或者一个item对象。
log(message[,level,component]) 该方法一个通过scrapy的logger发送日志文件的封装。详情点击。。
closed(reason) 当spider需要关闭时调用的方法,该方法给spider_closed信号的ignal_connect()提供了一个shortcut。
Spider arguments
spider的参数通过crawl命令行的-a选项进行传递。如 :scrapy crawl dingdian -a category=electronics
而spider可以通过__int_方法接收参数。由于__int__方法会默认调用任何spider传递进来的参数并将所有参数设置为属性值。所以可以随意调用,如self.category就等于electronics.
需要注意的是,-a选项传递的参数是一个字符串,所以并不能直接通过参数传递start_urls(它是个列表)。
3.Items
Item对象是用来收集爬取数据的简单容器。它提供了一个类似字典的API,语法简单(python class),类似于django的Models。由于scrapy只有一种字段类型Filed(),所以它比django简单得多的多。
4. Item Pipeline
spider爬取到一个item后,它就会被送往Pipeline进行下一步处理。每个item pipeline都是一个python类,一个用于接受item并对其进行处理的类。
item pipeline的四个典型应用是:清洗HTML数据、验证爬取的数据是否正确(与item中定义的是否一致)、检查数据是否有重复、将爬取的item存储到数据库中。
自定义的pipeline是一个pyhton 类,且必须包含以下方法:
process_item(self,item,spider) 该方法每个item pipeline的组件都得调用它,返回值为一个包含数据的字典 或 一个Item对象(或继承自Item的对象)
或一个Twisted Deferred 或者raise一个DropItem异常。丢弃的items就不再被其他pipeline组件处理。
参数:item(Item对象或字典)——爬取的item
spider(Spider对象)——爬取该item的spider
open_spider(self,spider) 当spider启动时就会调用此方法。若将爬取的数据保存在文件中,可以在该方法中打开文件。
close_spider(self,spider) 当spider关闭时就会调用此方法。若将爬取的数据保存在文件中,可以在该方法中关闭文件。
from_crawler(cls,crawler) 该方法用于对Crawler创建一个pipeline的实例。它必须返回一个pipeline的新实例,
Crawler对象可以对所有scrapy组件如settings和signals进行设置,是一种将pipeline的功能与scrapy相关联的方法。
此外,激活一个Item Pipeline组件还需在settings的ITEM_PIPELINES项中进行设置。
5. Feed exports
scrapy通过Feed Exports提供对爬取item进行存储的功能,可以存储成多种序列化格式和存储后端。
feed exports 默认提供四种序列化存储格式:json、json lines、CSV、XML,其他格式可以在settings的FEED_EXPORTERS项进行扩展。
JSON FEED_FORMAT:json
使用的Exporter:JsonItemExporter
注意:
JSON lines FEED_FORMAT:jsonlines
使用的Exporter:JsonLinesItemExporter
CSV FEED_FORMAT:csv
使用的Exporter:CsvItemExporter
注意:因为csv使用的是固定头部,若需指定输出的列以及列的顺序需要用FEED_EXPORT_FIELDS。
XML FEED_FORMAT:xml
使用的Exporter:XmlItemExporter
Pickle FEED_FORMAT:pickle
使用的Exporter:PickleItemExporter
Marshal FEED_FORMAT:marshal
使用的Exporter:MarshalItemExporter
6. Requests and Response
class scrapy.http.
Request
(url[, callback, method='GET', headers, body, cookies, meta, encoding='utf-8', priority=0, dont_filter=False, errback, flags])
url——一个字符串,表示请求的目的地址url
callback——一个可调用对象(callable),处理该请求返回响应的回调函数,默认为parse()
method——一个字符串,该请求的HTTP方法,默认为“GET”。
meta——一个字典,定义Request.meta属性的初始值。若给出该参数,该字典传递的值会被浅复制。
body——str或unicode,请求的主体。无论给出的该参数是str还是unicode,甚至不给出该参数(不给出时默认为空字符串),
最终存储的值都会是一个str类型,而不是unicode或None。所以若给出unicode,则会被自动编码成str(默认为utf-8编码)。
headers——一个字典,该请求的头部。字典的值可以为strings(一个健只有1个值时)也可以为lists(一个键有多个值)。若定义该参数为None,HTTP则根本不会传递该参数。
cookies——一个字典或列表,为列表格式时可以自定义cookie的domain和path属性,用于后续requests复用该cookies。大多数浏览器都会把一些网站(如购物站点)的cookies保存
在对应站点的文件夹里,以备后续使用。但是,如果你想关闭该功能,可以在Request.meta项中设置dont_merge_cookies键的值为True即可。
encoding——一个字符串,该请求的编码方式,默认为‘utf-8’。该编码方式用于将URL预编码和body参数传入unicode格式时转换使用。
priority——一个整数int,该请求的优先级别(默认为0),定义了scheduler处理该请求的优先级别。优先级越高,更早被处理。负数也可以,表征相对低的优先级。
dont_filter——布尔值,表示该请求是否会被scheduler过滤。用于重复多次发起一个完全相同的请求。默认为False。小心使用,容易陷入crawling loops。
errback——一个可调用对象,当处理请求过程中发生任何异常时就会调用该函数,包括404异常之类的。
flags——一个列表,传递给requests,用于登录等目的。
修改url、body时使用replace(),它返回一个特定参数更改而其余参数不变的request。
replace
([url, method, headers, body, cookies, meta, encoding, dont_filter, callback, errback])
回调函数的第一个参数是request发出的response。如 def parse1(self,response)。若想向回调函数中传递参数,需用到request的meta属性进行设置。
Requset subclass
class scrapy.http.
FormRequest
(url[, formdata, ...])
其中formdata是一个字典,或元组的一个迭代器,包含想要传递给request的body中的被url-encoded的HTML表单数据。
方法:from_response
(response[, formname=None, formid=None, formnumber=0, formdata=None, formxpath=None, formcss=None, clickdata=None, dont_click=False, ...])
用处:1.使用FormRequest实现通过HTTP POST传递数据:
return [FormRequest(url="http://www.example.com/post/action",
formdata={'name': 'John Doe', 'age': '27'},
callback=self.after_post)]
2.使用FormRequest的from_response()方法模拟账户登录:
import scrapy
class LoginSpider(scrapy.Spider):
name = 'example.com'
start_urls = ['http://www.example.com/users/login.php']
def parse(self, response):
return scrapy.FormRequest.from_response(
response,
formdata={'username': 'john', 'password': 'secret'},
callback=self.after_login
)
def after_login(self, response):
# check login succeed before going on
if "authentication failed" in response.body:
self.logger.error("Login failed")
return
# continue scraping with authenticated session...
class scrapy.http.
Response
(url[, status=200, headers=None, body=b'', flags=None, request=None])
url——该响应的url
status——HTTP状态码,默认为200
headers——一个类字典对象,包含了响应的头部文件,可以使用get()方法进行获取特定键下的第一个值或者使用getlist()方法获取响应名称下的所有值。
body——bytes,响应的主体。若想得到解码后的str文本(python3中,python2为unicode)可以使用response.text方法
flags——同上
request——一个请求对象,表示生产该响应的request,定义了Resposne.request的初始值。
Response subclass
class scrapy.http.
TextResponse
(url[, encoding[, ...]])
该子类就是在基类Response上添加了编码能力。
class scrapy.http.
HtmlResponse
(url[, ...])
该类是TextResponse的子类,通过浏览 HTML 的meta http-equiv属性添加了编码自动查找功能。
class scrapy.http.
XmlResponse
(url[, ...])
该类也是TextResponse的子类。通过浏览XML的装饰行进行编码自动查找。
7.Link Extractors
Link Extractors对象用于仅仅为了从web pages中提取链接时使用。scrapy提供了一个scrapy.linkextractors.LinkExtractor,
但你也可以根据自己的特定需求,创建一个简单的接口来自定义Link Extractors。
唯一一个每个link extractor都具有的方法是extract_links,它用于接收resposne对象和返回一个scrapy.link.Link对象的列表。
scrapy内置了一个link extractors,即scrapy.linkextractors模块:
from scrapy.linkextractors import LinkExtractor
默认的link extractors是LinkExtractor,不过它跟LxmlLinkExtractor一模一样。
8.Settings
scrapy的settings可以对所有组件进行自定义设置,包括the core、extensions、pipelines和spiders本身。
settings配置的路径主要有以下几种:
1.command line options命令行选项(-s 或 --set)
如:scrapy crawl myspider -s LOG_FILE=scrapy.log
2.settings per-spider在每个spider单独进行设置,通过custom_settings属性
如:class MySpider(scrapy.Spider):
name = 'myspider'
custom_settings = {
'SOME_SETTING': 'some value',
}
3.projects settings module配置该项目的settings.py文件,通常在对应spider文件中创建settings.py文件进行设置。
4.default settings per-command命令行中通过default_settings属性进行设置
5.default global settings对默认的全局设置进行更改,即更改scrapy.settings.default_settings模块。
在spider中通过self.settings属性来获取属性值。
class MySpider(scrapy.Spider):
name = 'myspider'
start_urls = ['http://example.com']
def parse(self, response):
print("Existing settings: %s" % self.settings.attributes.keys())
注意,这样获取的属性值是spider初始化后的基类spider中的设置,若想在初始化之前即在spider的__init__()方法中获取,需要重写from_crawl()方法。
class MyExtension(object):
def __init__(self, log_is_enabled=False):
if log_is_enabled:
print("log is enabled!")
@classmethod
def from_crawler(cls, crawler):
settings = crawler.settings
return cls(settings.getbool('LOG_ENABLED'))
9.Exceptions
scrapy中内置的所有异常:
exception scrapy.exceptions.
DropItem
在item pipeline阶段使处理item中断就必须引发该异常。
exception scrapy.exceptions.
CloseSpider
(reason='cancelled')
当发出请求的spider被关闭或停止时,回调函数中就应引发该异常,并在reason中给出原因。
exceptionscrapy.exceptions.
DontCloseSpider
exceptionscrapy.exceptions.
IgnoreRequest
exceptionscrapy.exceptions.
NotConfigured
exceptionscrapy.exceptions.
NotSupported