拆解 scrapy.Spider
本次采集的目标站点为:优设网
每次创建一个 spider
文件之后,都会默认生成如下代码:
1
2
3
4
5
6
7
8
|
import scrapy
class UiSpider(scrapy.Spider):
name = 'ui'
allowed_domains = [ 'www.uisdc.com' ]
start_urls = [ 'http://www.uisdc.com/' ]
def parse( self , response):
self .log()
|
继承的基类 scrapy.Spider
自然就成了我们要研究的第一个内容,进入其源码,发现如下内容。
scrapy.Spider 核心实现的是 start_requests 方法
Spider 主要进行的操作就是初始化 Request 请求,而这些都是通过 start_requests
实现的,详细代码为:
1
2
|
for url in self .start_urls:
yield Request(url, dont_filter = True )
|
对 start_requests
方法,你可以自己编写同名函数覆盖修改,编写时发现了 make_requests_from_url
方法,该方法在最新版本的 scrapy
中已经被废除。
重写 start_requests 方法 ,需要注意重写时,必须返回一个可迭代对象,并且该对象包含 spider
用于爬取的第 1 个 Request
,由于 scrapy
只调用一次该方法,所以你可以将登录站点请求放置到该方法中。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import scrapy
from scrapy.http import Request
class UiSpider(scrapy.Spider):
name = 'ui'
allowed_domains = [ 'www.uisdc.com' ]
start_urls = [ 'http://www.uisdc.com/' ]
def start_requests( self ):
print ( "重写 start_requests" )
yield Request( self .start_urls[ 0 ])
def parse( self , response):
print (response)
|
将登录信息放置到 start_requests
中,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
import scrapy
from scrapy.http import FormRequest
class UiSpider(scrapy.Spider):
name = 'ui'
allowed_domains = [ 'www.uisdc.com' ]
start_urls = [ 'http://www.uisdc.com/' ]
def start_requests( self ):
print ( "手动 start_requests" )
yield FormRequest( "https://httpbin.org/post" , formdata = { "user" : "ca" }, callback = self .parse)
def parse( self , response):
print (response.text)
|
scrapy.Spider 属性值
name 属性:
表示爬虫名称,spider 的名称用于 scrapy
定位爬虫,所以非常重要,一般常见的名称方式是使用网站域名(domain),命名 spider,例如 baidu.com
命名为 baidu
,但是工作喜欢还是携带 .com
后缀。
allowed_domains 属性:
该属性需要配置 offsiteMiddleware
使用,当该中间件启用之后,待采集 URL 的域名如果不在 allowed_domains
列表中,会被禁止访问。domains
内容添加,假设你的目标 URL 是 http://www.baidu.com/123.html
,仅填写 baidu.com
即可。
start_urls 属性:
起始的 URL 列表,主要用于 start_request
方法进行迭代。
custom_settings 属性:
自定义配置,可以覆盖 settings.py
的配置,以字典格式赋值。
1
2
3
|
custom_settings = {
"ROBOTSTXT_OBEY" : False # 不请求 robot.txt 文件
}
|
crawler 属性:
该属性在爬虫启动后,由类方法 from_crawler()
设置。
settings 属性:
指定配置文件的实例。
logger 属性:
spider 日志输出对象,默认以 spider 名称创建,可以自定义。
1
2
|
self .logger.info( '输出响应地址 %s' , response.url)
logger.info( '输出响应地址 %s' , response.url)
|
补充一下 scrapy 日志级别
在 settings.py
中设置 log
级别,只需要增加一行代码:
1
|
LOG_LEVEL = 'WARNING'
|
设置为 WARNING
级别,会发现 scrapy 默认的各种调试信息,都不在控制台输出。
scrapy
日志级别与 logging
模块一致。
CRITICAL:严重错误;
ERROR :一般错误;
WARNING: 警告信息;
INFO :一般信息;
DEBUG:调试信息。
在 scrapy
中的 settings
中关于日志的配置如下:
LOG_ENABLED
:默认: True,表示启用 logging;
LOG_ENCODING
: 默认: utf-8,logging 使用的编码;
LOG_FILE
默认: None,日志保存的文件名;
LOG_LEVEL
: 默认 DEBUG ,log 的最低级别。
scrapy.Spider 实例方法与类方法
from_crawler 类方法
在查看源码之后,该方法的功能会比较清晰。
1
2
3
4
5
6
7
8
9
10
|
@classmethod
def from_crawler( cls , crawler, * args, * * kwargs):
spider = cls ( * args, * * kwargs)
spider._set_crawler(crawler)
return spider
def _set_crawler( self , crawler):
self .crawler = crawler
self .settings = crawler.settings
crawler.signals.connect( self .close, signals.spider_closed)
|
该方法设置了 crawler
和 settings
两个属性,该方法在上一篇博客已经有所涉及,直接回顾即可。
parse 方法
当请求(Request)没有指定回调参数(callback)时,该方法是 scrapy
用来处理响应的默认回调方法。
log 方法
使用 self.log()
方法记录日志。
学习到这里,对 Spider 模块有了一个比较整体的认识。
爬取优设网
接下来进入爬虫采集相关代码编写,有了前文知识铺垫之后,采集代码就变得非常简单了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
import scrapy
from uisdc.items import UisdcItem
class UiSpider(scrapy.Spider):
name = 'ui'
allowed_domains = [ 'www.uisdc.com' ]
start_urls = [ 'https://www.uisdc.com/archives' ]
custom_settings = {
"ROBOTSTXT_OBEY" : False
}
def parse( self , response):
# print(response.text)
# self.log("测试是否有数据输出", logging.WARNING)
items = response.xpath( '//div[@id="archive_list"]/div/div[1]/div[1]/div[contains(@class,"item-article")]' )
for i in items:
item = UisdcItem()
title = i.xpath( ".//h2[@class='item-title']/a/text()" ).extract_first()
author = i.xpath( ".//h3[@class='meta-name']/text()" ).extract_first()
tag = i.xpath( ".//div[@class='meta-tag']/a/text()" ).extract_first()
item[ "title" ] = title
item[ "author" ] = author
item[ "tag" ] = tag
yield item
|
接下来修改源码,增加 ** Item Loaders** 填充容器机制。通过 from scrapy.loader import ItemLoader
导入新类,该类的构造函数如下:
1
|
def __init__( self , item = None , selector = None , response = None , parent = None , * * context)
|
其中 item
是容器类,selector
为 Selector 对象,提取填充数据的选择器,response
为 Response 响应对象。
代码修改之后得到如下代码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import scrapy
from uisdc.items import UisdcItem
from scrapy.loader import ItemLoader
class UiSpider(scrapy.Spider):
name = 'ui'
allowed_domains = [ 'www.uisdc.com' ]
start_urls = [ 'https://www.uisdc.com/archives' ]
custom_settings = {
"ROBOTSTXT_OBEY" : False
}
def parse( self , response):
items = response.xpath( '//div[@id="archive_list"]/div/div[1]/div[1]/div[contains(@class,"item-article")]' )
for i in items:
l = ItemLoader(item = UisdcItem(), selector = i)
l.add_xpath( 'title' , ".//h2[@class='item-title']/a/text()" )
l.add_xpath( 'author' , ".//h3[@class='meta-name']/text()" )
l.add_xpath( 'tag' , ".//div[@class='meta-tag']/a/text()" )
yield l.load_item()
|
其中需要注意 l = ItemLoader(item=UisdcItem(), selector=i) 使用 selector
参数,并赋值为迭代变量 i
,如果使用 response
会得到重复数据。
最后,当所有数据被收集起来之后, 调用 ItemLoader.load_item()
方法, 返回 Item
对象。
输出 item
对象,发现每一个数据都是列表。
1
2
3
|
{ 'author' : [ '土拨鼠' ],
'tag' : [ '产品设计' ],
'title' : [ '6000+干货!资深总监的四条产品设计工作观(附私藏神器包)' ]}
|
接下来需要处理每一项的值,ItemLoader 得到的数据,在存入 item
容器前,是支持对数据进行预处理的,即输入处理器和输出处理器,修改 items.py
文件。
1
2
3
4
5
6
7
8
9
10
11
12
|
from scrapy.item import Item, Field
from scrapy.loader.processors import MapCompose, TakeFirst
def ext(value):
return "新闻:" + value
class UisdcItem(Item):
# define the fields for your item here like:
title = Field(
input_processor = MapCompose(ext),
output_processor = TakeFirst()
)
author = Field(output_processor = TakeFirst())
tag = Field(output_processor = TakeFirst())
|
Field 字段的两个参数:
输入处理器(input_processor):可以在传进来的值做一些预处理。
输出处理器(output_processor) :输出值前最后的一步处理。
其中用到了 TakeFirst()
,返回第一个非空(non-null/ non-empty
)值,常用于单值字段的输出处理器,无参数。
还用到了 MapCompose
,能把多个函数执行的结果按顺序组合起来,产生最终的输出,通常用于输入处理器。
其余内置的处理器如下
Identity:不进行任何处理,返回原来的数据,无参数;
Join:返回用分隔符连接后的值,分隔符默认为空格;
Compose:用给定的多个函数的组合,来构造处理器,list 对象一次被传递到各个函数中,由最后一个函数返回整个处理器的输出,默认情况下遇到 None
值(list 中有 None 值)的时候停止处理,可以通过传递参数 stop_on_none = False
改变这种行为;
MapCompose:输入值是被迭代的处理的,List 对象中的每一个元素被单独传入,依次执行对应函数。
关于 item loader 还有一些其它的知识点,我们后面再聊。
以上就是python scrapy拆解查看Spider类爬取优设网极细讲解的详细内容,更多关于scrapy拆解Spider类爬取优设网的资料请关注服务器之家其它相关文章!
原文链接:https://blog.csdn.net/hihell/article/details/120936534