W3Cschool
恭喜您成為首批注冊(cè)用戶
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
既然您知道了如何從頁(yè)面中提取數(shù)據(jù),那么讓我們看看如何從頁(yè)面中跟蹤鏈接。
第一件事是提取到我們要跟蹤的頁(yè)面的鏈接。檢查我們的頁(yè)面,我們可以看到有一個(gè)鏈接指向下一個(gè)帶有以下標(biāo)記的頁(yè)面:
<ul class="pager">
<li class="next">
<a href="/page/2/">Next <span aria-hidden="true">→</span></a>
</li>
</ul>
我們可以嘗試在外殼中提?。?/p>
>>> response.css('li.next a').get()
'<a href="/page/2/">Next <span aria-hidden="true">→</span></a>'
這將獲取anchor元素,但我們需要該屬性 ?href
? . 為此,Scrapy支持CSS擴(kuò)展,允許您選擇屬性內(nèi)容,如下所示:
>>> response.css('li.next a::attr(href)').get()
'/page/2/'
還有一個(gè) ?attrib
? 可用屬性(請(qǐng)參見 選擇元素屬性 更多信息):
>>> response.css('li.next a').attrib['href']
'/page/2/'
現(xiàn)在讓我們看看我們的spider被修改為遞歸地跟蹤下一頁(yè)的鏈接,從中提取數(shù)據(jù):
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = [
'http://quotes.toscrape.com/page/1/',
]
def parse(self, response):
for quote in response.css('div.quote'):
yield {
'text': quote.css('span.text::text').get(),
'author': quote.css('small.author::text').get(),
'tags': quote.css('div.tags a.tag::text').getall(),
}
next_page = response.css('li.next a::attr(href)').get()
if next_page is not None:
next_page = response.urljoin(next_page)
yield scrapy.Request(next_page, callback=self.parse)
現(xiàn)在,在提取數(shù)據(jù)之后, ?parse()
? 方法查找到下一頁(yè)的鏈接,并使用 ?urljoin()
? 方法(因?yàn)殒溄涌梢允窍鄬?duì)的),并生成對(duì)下一頁(yè)的新請(qǐng)求,將自身注冊(cè)為回調(diào),以處理下一頁(yè)的數(shù)據(jù)提取,并保持爬行在所有頁(yè)中進(jìn)行。
這里您看到的是scrapy的以下鏈接機(jī)制:當(dāng)您在回調(diào)方法中生成一個(gè)請(qǐng)求時(shí),scrapy將計(jì)劃發(fā)送該請(qǐng)求,并注冊(cè)一個(gè)回調(diào)方法,以便在該請(qǐng)求完成時(shí)執(zhí)行。
使用它,您可以構(gòu)建復(fù)雜的爬蟲程序,這些爬蟲程序根據(jù)您定義的規(guī)則跟蹤鏈接,并根據(jù)所訪問的頁(yè)面提取不同類型的數(shù)據(jù)。
在我們的示例中,它創(chuàng)建了一種循環(huán),跟蹤到下一頁(yè)的所有鏈接,直到找不到一個(gè)為止——這對(duì)于爬行博客、論壇和其他帶有分頁(yè)的站點(diǎn)很方便。
作為創(chuàng)建請(qǐng)求對(duì)象的快捷方式,您可以使用 ?response.follow
? ::
import scrapy
class QuotesSpider(scrapy.Spider):
name = "quotes"
start_urls = [
'http://quotes.toscrape.com/page/1/',
]
def parse(self, response):
for quote in response.css('div.quote'):
yield {
'text': quote.css('span.text::text').get(),
'author': quote.css('span small::text').get(),
'tags': quote.css('div.tags a.tag::text').getall(),
}
next_page = response.css('li.next a::attr(href)').get()
if next_page is not None:
yield response.follow(next_page, callback=self.parse)
不像Scrapy.Request, ?response.follow
? 直接支持相對(duì)URL-無需調(diào)用URLJOIN。注意 ?response.follow
? 只返回一個(gè)請(qǐng)求實(shí)例;您仍然需要生成這個(gè)請(qǐng)求。
也可以將選擇器傳遞給 ?response.follow
? 而不是字符串;此選擇器應(yīng)提取必要的屬性:
for href in response.css('ul.pager a::attr(href)'):
yield response.follow(href, callback=self.parse)
為了 ?<a>
? 元素有一個(gè)快捷方式: ?response.follow
? 自動(dòng)使用其href屬性。因此代碼可以進(jìn)一步縮短:
for a in response.css('ul.pager a'):
yield response.follow(a, callback=self.parse)
要從iterable創(chuàng)建多個(gè)請(qǐng)求,可以使用 ?response.follow_all
? 取而代之的是:
anchors = response.css('ul.pager a')
yield from response.follow_all(anchors, callback=self.parse)
或者,進(jìn)一步縮短:
yield from response.follow_all(css='ul.pager a', callback=self.parse)
下面是另一個(gè)spider,它演示回調(diào)和以下鏈接,這次是為了抓取作者信息:
import scrapy
class AuthorSpider(scrapy.Spider):
name = 'author'
start_urls = ['http://quotes.toscrape.com/']
def parse(self, response):
author_page_links = response.css('.author + a')
yield from response.follow_all(author_page_links, self.parse_author)
pagination_links = response.css('li.next a')
yield from response.follow_all(pagination_links, self.parse)
def parse_author(self, response):
def extract_with_css(query):
return response.css(query).get(default='').strip()
yield {
'name': extract_with_css('h3.author-title::text'),
'birthdate': extract_with_css('.author-born-date::text'),
'bio': extract_with_css('.author-description::text'),
}
這個(gè)蜘蛛將從主頁(yè)開始,它將跟蹤所有指向作者頁(yè)面的鏈接,調(diào)用 ?parse_author
? 它們的回調(diào),以及與 ?parse
? 像我們以前看到的那樣回?fù)堋?/p>
這里,我們把回電傳遞給 ?response.follow_all
? 作為使代碼更短的位置參數(shù);它也適用于 ?Request
? .
這個(gè) ?parse_author
? 回調(diào)定義了一個(gè)助手函數(shù),用于從CSS查詢中提取和清理數(shù)據(jù),并用作者數(shù)據(jù)生成python dict。
這個(gè)蜘蛛展示的另一個(gè)有趣的事情是,即使同一作者引用了很多話,我們也不需要擔(dān)心多次訪問同一作者頁(yè)面。默認(rèn)情況下,scrappy過濾掉對(duì)已經(jīng)訪問過的URL的重復(fù)請(qǐng)求,避免了由于編程錯(cuò)誤而太多地訪問服務(wù)器的問題。這可以通過設(shè)置進(jìn)行配置 ?DUPEFILTER_CLASS
? .
希望到目前為止,您已經(jīng)很好地了解了如何使用scrappy跟蹤鏈接和回調(diào)的機(jī)制。
作為另一個(gè)利用以下鏈接機(jī)制的蜘蛛示例,請(qǐng)查看 ?CrawlSpider
? 類,該類用于實(shí)現(xiàn)一個(gè)小規(guī)則引擎,您可以使用該引擎在上面編寫爬蟲程序。
另外,一個(gè)常見的模式是使用:ref:`trick將其他數(shù)據(jù)傳遞給回調(diào)<topics-request-response-ref-request-callback-arguments>`來構(gòu)建包含來自多個(gè)頁(yè)面的數(shù)據(jù)的項(xiàng)目。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話:173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: