Scrapy笔记03- Spider详解

Spider是爬虫框架的核心,爬取流程以下:

  1. 先初始化要求URL列表,并指定下载后处置response的回调函数。初次要求URL通过start_urls指定,调用start_requests()发生Request对象,然后注册parse办法作为回调
  2. 在parse回调中解析response并返回字典,Item对象,Request对象或它们的迭代对象。Request对象还会包括回调函数,以后Scrapy下载完后会被这里注册的回调函数处置。
  3. 在回调函数里面,你通过应用选择器(一样可以应用BeautifulSoup,lxml或其他工具)解析页面内容,并生成解析后的成果Item。
  4. 最后返回的这些Item通常会被持久化到数据库中(应用Item Pipeline)或应用Feed exports将其保留到文件中。

虽然这个流程合适于所有的蜘蛛,但是Scrapy里面为不同的应用目标实现了一些常见的Spider。下面我们把它们列出来。

CrawlSpider

连接爬取蜘蛛,专门为那些爬取有特定规律的连接内容而预备的。如果你认为它还不足以合适你的需求,可以先继承它然后笼罩相应的办法,或自定义Spider也行。

它除从scrapy.Spider类继承的属性外,还有一个新的属性rules,它是一个Rule对象列表,每一个Rule对象定义了某个规矩,如果多个Rule匹配一个衔接,那末应用第一个,依据定义的次序。

一个详细的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from coolscrapy.items import HuxiuItem
import scrapy
from scrapy.spiders import CrawlSpider, Rule
from scrapy.linkextractors import LinkExtractor


class LinkSpider(CrawlSpider):
name = "link"
allowed_domains = ["huxiu.com"]
start_urls = [
"http://www.huxiu.com/index.php"
]

rules = (
# 提取匹配正则式"/group?f=index_group"连接 (但是不能匹配"deny.php")
# 并且会递归爬取(如果没有定义callback,默许follow=True).
Rule(LinkExtractor(allow=("/group?f=index_group", ), deny=("deny\.php", ))),
# 提取匹配"/article/\d+/\d+.html"的连接,并应用parse_item来解析它们下载后的内容,不递归
Rule(LinkExtractor(allow=("/article/\d+/\d+\.html", )), callback="parse_item"),
)

def parse_item(self, response):
self.logger.info("Hi, this is an item page! %s", response.url)
detail = response.xpath("//div[@class="article-wrap"]")
item = HuxiuItem()
item["title"] = detail.xpath("h1/text()")[0].extract()
item["link"] = response.url
item["posttime"] = detail.xpath(
"div[@class="article-author"]/span[@class="article-time"]/text()")[0].extract()
print(item["title"],item["link"],item["posttime"])
yield item

XMLFeedSpider

XML定阅蜘蛛,用来爬取XML情势的定阅内容,通过某个指定的节点来遍历。可应用iternodes, xml, 和html三种情势的迭代器,不过当内容比拟多的时候推举应用iternodes,默许也是它,可以节俭内存晋升性状,不须要将全部DOM加载到内存中再解析。而应用html可以处置XML有格局毛病的内容。处置XML的时候最好先Removing namespaces

接下来我通过爬取我的博客定阅XML来展现它的应用办法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
from coolscrapy.items import BlogItem
import scrapy
from scrapy.spiders import XMLFeedSpider


class XMLSpider(XMLFeedSpider):
name = "xml"
namespaces = [("atom", "http://www.w3.org/2005/Atom")]
allowed_domains = ["github.io"]
start_urls = [
"http://www.pycoding.com/atom.xml"
]
iterator = "xml" # 缺省的iternodes,貌似对有namespace的xml不行
itertag = "atom:entry"

def parse_node(self, response, node):
# self.logger.info("Hi, this is a <%s> node!", self.itertag)
item = BlogItem()
item["title"] = node.xpath("atom:title/text()")[0].extract()
item["link"] = node.xpath("atom:link/@href")[0].extract()
item["id"] = node.xpath("atom:id/text()")[0].extract()
item["published"] = node.xpath("atom:published/text()")[0].extract()
item["updated"] = node.xpath("atom:updated/text()")[0].extract()
self.logger.info("|".join([item["title"],item["link"],item["id"],item["published"]]))
return item

CSVFeedSpider

这个跟上面的XMLFeedSpider很相似,区分在于它会一行一行的迭代,而不是一个节点一个节点的迭代。每次迭代行的时候会调用parse_row()办法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from coolscrapy.items import BlogItem
from scrapy.spiders import CSVFeedSpider


class CSVSpider(CSVFeedSpider):
name = "csv"
allowed_domains = ["example.com"]
start_urls = ["http://www.example.com/feed.csv"]
delimiter = ";"
quotechar = """
headers = ["id", "name", "description"]

def parse_row(self, response, row):
self.logger.info("Hi, this is a row!: %r", row)
item = BlogItem()
item["id"] = row["id"]
item["name"] = row["name"]
return item

SitemapSpider

站点地图蜘蛛,许可你应用Sitemaps发明URL后爬取全部站点。还支撑嵌套的站点地图和从robots.txt中发明站点URL