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