Scrapy1.4最新官方文檔總結(jié) 2 Tutorial


Scrapy1.4最新官方文檔總結(jié) 1 介紹·安裝
Scrapy1.4最新官方文檔總結(jié) 2 Tutorial
Scrapy1.4最新官方文檔總結(jié) 3 命令行工具


這是官方文檔的Tutorial(https://docs.scrapy.org/en/latest/intro/tutorial.html)目锭。

推薦四個(gè)Python學(xué)習(xí)資源:

創(chuàng)建項(xiàng)目

使用命令:

scrapy startproject tutorial

會生成以下文件:

在tutorial/spiders文件夾新建文件quotes_spider.py奕剃,它的代碼如下:

import scrapy

class QuotesSpider(scrapy.Spider):
    name = "quotes"

    def start_requests(self):
        urls = [
            'http://quotes.toscrape.com/page/1/',
            'http://quotes.toscrape.com/page/2/',
        ]
        for url in urls:
            yield scrapy.Request(url=url, callback=self.parse)

    def parse(self, response):
        page = response.url.split("/")[-2]
        filename = 'quotes-%s.html' % page
        with open(filename, 'wb') as f:
            f.write(response.body)
        self.log('Saved file %s' % filename)

start_requests方法返回 scrapy.Request對象。每收到一個(gè)捐下,就實(shí)例化一個(gè)Response對象邢滑,并調(diào)用和request綁定的調(diào)回方法(即parse)蹂午,將response作為參數(shù)。

切換到根目錄翔怎,運(yùn)行爬蟲:

scrapy crawl quotes
輸出日志

根目錄下會產(chǎn)生兩個(gè)文件窃诉,quotes-1.html和quotes-2.html。

另一種方法是定義一個(gè)包含URLs的類赤套,parse( )是Scrapy默認(rèn)的調(diào)回方法飘痛,即使沒有指明調(diào)回,也會執(zhí)行:

import scrapy

class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
        'http://quotes.toscrape.com/page/2/',
    ]

    def parse(self, response):
        page = response.url.split("/")[-2]
        filename = 'quotes-%s.html' % page
        with open(filename, 'wb') as f:
            f.write(response.body)

提取信息

學(xué)習(xí)Scrapy提取信息的最好方法是使用Scrapy Shell容握,win7 shell運(yùn)行:

scrapy shell "http://quotes.toscrape.com/page/1/"

或者宣脉,gitbash運(yùn)行,注意有單引號和雙引號的區(qū)別:

scrapy shell 'http://quotes.toscrape.com/page/1/'

輸出如下:


利用CSS進(jìn)行提忍奘稀:

>>> response.css('title')
[<Selector xpath='descendant-or-self::title' data='<title>Quotes to Scrape</title>'>]

只提取標(biāo)題的文本:

>>> response.css('title::text').extract()
['Quotes to Scrape']

::text表示只提取文本塑猖,去掉的話,顯示如下:

>>> response.css('title').extract()
['<title>Quotes to Scrape</title>']

因?yàn)榉祷貙ο笫且粋€(gè)列表谈跛,只提取第一個(gè)的話羊苟,使用:

>>> response.css('title::text').extract_first()
'Quotes to Scrape'

或者,使用序號:

>>> response.css('title::text')[0].extract()
'Quotes to Scrape'

前者更好币旧,可以避免潛在的序號錯(cuò)誤践险。

除了使用 extract()和 extract_first(),還可以用正則表達(dá)式:

>>> response.css('title::text').re(r'Quotes.*')
['Quotes to Scrape']
>>> response.css('title::text').re(r'Q\w+')
['Quotes']
>>> response.css('title::text').re(r'(\w+) to (\w+)')
['Quotes', 'Scrape']
提取日志

XPath簡短介紹

Scrapy還支持XPath:

>>> response.xpath('//title')
[<Selector xpath='//title' data='<title>Quotes to Scrape</title>'>]
>>> response.xpath('//title/text()').extract_first()
'Quotes to Scrape'

其實(shí)吹菱,CSS是底層轉(zhuǎn)化為XPath的巍虫,但XPath的功能更為強(qiáng)大,比如它可以選擇包含next page的鏈接鳍刷。更多見 using XPath with Scrapy Selectors here占遥。

繼續(xù)提取名人名言

http://quotes.toscrape.com的每個(gè)名言的HTML結(jié)構(gòu)如下:

<div class="quote">
    <span class="text">“The world as we have created it is a process of our
    thinking. It cannot be changed without changing our thinking.”</span>
    <span>
        by <small class="author">Albert Einstein</small>
        <a href="/author/Albert-Einstein">(about)</a>
    </span>
    <div class="tags">
        Tags:
        <a class="tag" href="/tag/change/page/1/">change</a>
        <a class="tag" href="/tag/deep-thoughts/page/1/">deep-thoughts</a>
        <a class="tag" href="/tag/thinking/page/1/">thinking</a>
        <a class="tag" href="/tag/world/page/1/">world</a>
    </div>
</div>

使用:

$ scrapy shell "http://quotes.toscrape.com"

將HTML的元素以列表的形式提取出來:

response.css("div.quote")

只要第一個(gè):

quote = response.css("div.quote")[0]

提取出標(biāo)題、作者输瓜、標(biāo)簽:

>>> title = quote.css("span.text::text").extract_first()
>>> title
'“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”'
>>> author = quote.css("small.author::text").extract_first()
>>> author
'Albert Einstein'

標(biāo)簽是一組字符串:

>>> tags = quote.css("div.tags a.tag::text").extract()
>>> tags
['change', 'deep-thoughts', 'thinking', 'world']

弄明白了提取每個(gè)名言瓦胎,現(xiàn)在提取所有的:

>>> for quote in response.css("div.quote"):
...     text = quote.css("span.text::text").extract_first()
...     author = quote.css("small.author::text").extract_first()
...     tags = quote.css("div.tags a.tag::text").extract()
...     print(dict(text=text, author=author, tags=tags))
{'tags': ['change', 'deep-thoughts', 'thinking', 'world'], 'author': 'Albert Einstein', 'text': '“The world as we have created it is a process of our thinking. It cannot be changed without changing our thinking.”'}
{'tags': ['abilities', 'choices'], 'author': 'J.K. Rowling', 'text': '“It is our choices, Harry, that show what we truly are, far more than our abilities.”'}
    ... a few more of these, omitted for brevity
>>>

用爬蟲提取信息

使用Python的yield:

import scrapy

class QuotesSpider(scrapy.Spider):
    name = "quotes"
    start_urls = [
        'http://quotes.toscrape.com/page/1/',
        'http://quotes.toscrape.com/page/2/',
    ]

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').extract_first(),
                'author': quote.css('small.author::text').extract_first(),
                'tags': quote.css('div.tags a.tag::text').extract(),
            }

運(yùn)行爬蟲芬萍,日志如下:

2016-09-19 18:57:19 [scrapy.core.scraper] DEBUG: Scraped from <200 http://quotes.toscrape.com/page/1/>
{'tags': ['life', 'love'], 'author': 'André Gide', 'text': '“It is better to be hated for what you are than to be loved for what you are not.”'}
2016-09-19 18:57:19 [scrapy.core.scraper] DEBUG: Scraped from <200 http://quotes.toscrape.com/page/1/>
{'tags': ['edison', 'failure', 'inspirational', 'paraphrased'], 'author': 'Thomas A. Edison', 'text': "“I have not failed. I've just found 10,000 ways that won't work.”"}

保存數(shù)據(jù)

最便捷的方式是使用feed export,保存為json搔啊,命令如下:

scrapy crawl quotes -o quotes.json

保存為json lines:

scrapy crawl quotes -o quotes.jl

保存為csv:

scrapy crawl quotes -o quotes.csv

提取下一頁

首先看下一頁的鏈接:

<ul class="pager">
    <li class="next">
        <a href="/page/2/">Next <span aria-hidden="true">→</span></a>
    </li>
</ul>

提取出來:

>>> response.css('li.next a').extract_first()
'<a href="/page/2/">Next <span aria-hidden="true">→</span></a>'

只要href:

>>> response.css('li.next a::attr(href)').extract_first()
'/page/2/'

利用urljoin生成完整的url螃成,生成下一頁的請求,就可以循環(huán)抓取了:

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').extract_first(),
                'author': quote.css('small.author::text').extract_first(),
                'tags': quote.css('div.tags a.tag::text').extract(),
            }

        next_page = response.css('li.next a::attr(href)').extract_first()
        if next_page is not None:
            next_page = response.urljoin(next_page)
            yield scrapy.Request(next_page, callback=self.parse)

更簡潔的方式是使用 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').extract_first(),
                'author': quote.css('span small::text').extract_first(),
                'tags': quote.css('div.tags a.tag::text').extract(),
            }

        next_page = response.css('li.next a::attr(href)').extract_first()
        if next_page is not None:
            yield response.follow(next_page, callback=self.parse)

直接將參數(shù)傳遞給response.follow:

for href in response.css('li.next a::attr(href)'):
    yield response.follow(href, callback=self.parse)

對于a標(biāo)簽今缚,response.follow可以直接使用它的屬性调窍,這樣就可以變得更簡潔:

for a in response.css('li.next a'):
    yield response.follow(a, callback=self.parse)

下面這個(gè)爬蟲提取作者信息,使用了調(diào)回和自動獲取下一頁:

import scrapy

class AuthorSpider(scrapy.Spider):
    name = 'author'

    start_urls = ['http://quotes.toscrape.com/']

    def parse(self, response):
        # 作者鏈接
        for href in response.css('.author + a::attr(href)'):
            yield response.follow(href, self.parse_author)

        # 分頁鏈接
        for href in response.css('li.next a::attr(href)'):
            yield response.follow(href, self.parse)

    def parse_author(self, response):
        def extract_with_css(query):
            return response.css(query).extract_first().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'),
        }

使用爬蟲參數(shù)

在命令行中使用參數(shù)旧蛾,只要添加 -a:

scrapy crawl quotes -o quotes-humor.json -a tag=humor

將humor傳遞給tag:

import scrapy

class QuotesSpider(scrapy.Spider):
    name = "quotes"

    def start_requests(self):
        url = 'http://quotes.toscrape.com/'
        tag = getattr(self, 'tag', None)
        if tag is not None:
            url = url + 'tag/' + tag
        yield scrapy.Request(url, self.parse)

    def parse(self, response):
        for quote in response.css('div.quote'):
            yield {
                'text': quote.css('span.text::text').extract_first(),
                'author': quote.css('small.author::text').extract_first(),
            }

        next_page = response.css('li.next a::attr(href)').extract_first()
        if next_page is not None:
            yield response.follow(next_page, self.parse)

更多例子

https://github.com/scrapy/quotesbot上有個(gè)叫做quotesbot的爬蟲莽龟,提供了CSS和XPath兩種寫法:

import scrapy

class ToScrapeCSSSpider(scrapy.Spider):
    name = "toscrape-css"
    start_urls = [
        'http://quotes.toscrape.com/',
    ]

    def parse(self, response):
        for quote in response.css("div.quote"):
            yield {
                'text': quote.css("span.text::text").extract_first(),
                'author': quote.css("small.author::text").extract_first(),
                'tags': quote.css("div.tags > a.tag::text").extract()
            }

        next_page_url = response.css("li.next > a::attr(href)").extract_first()
        if next_page_url is not None:
            yield scrapy.Request(response.urljoin(next_page_url))
import scrapy

class ToScrapeSpiderXPath(scrapy.Spider):
    name = 'toscrape-xpath'
    start_urls = [
        'http://quotes.toscrape.com/',
    ]

    def parse(self, response):
        for quote in response.xpath('//div[@class="quote"]'):
            yield {
                'text': quote.xpath('./span[@class="text"]/text()').extract_first(),
                'author': quote.xpath('.//small[@class="author"]/text()').extract_first(),
                'tags': quote.xpath('.//div[@class="tags"]/a[@class="tag"]/text()').extract()
            }

        next_page_url = response.xpath('//li[@class="next"]/a/@href').extract_first()
        if next_page_url is not None:
            yield scrapy.Request(response.urljoin(next_page_url))

Scrapy1.4最新官方文檔總結(jié) 1 介紹·安裝
Scrapy1.4最新官方文檔總結(jié) 2 Tutorial
Scrapy1.4最新官方文檔總結(jié) 3 命令行工具


最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市锨天,隨后出現(xiàn)的幾起案子毯盈,更是在濱河造成了極大的恐慌,老刑警劉巖病袄,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件搂赋,死亡現(xiàn)場離奇詭異,居然都是意外死亡陪拘,警方通過查閱死者的電腦和手機(jī)厂镇,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來左刽,“玉大人捺信,你說我怎么就攤上這事∏烦眨” “怎么了迄靠?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長喇辽。 經(jīng)常有香客問我掌挚,道長,這世上最難降的妖魔是什么菩咨? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任吠式,我火速辦了婚禮,結(jié)果婚禮上抽米,老公的妹妹穿的比我還像新娘特占。我一直安慰自己,他們只是感情好云茸,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布是目。 她就那樣靜靜地躺著,像睡著了一般标捺。 火紅的嫁衣襯著肌膚如雪懊纳。 梳的紋絲不亂的頭發(fā)上揉抵,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天,我揣著相機(jī)與錄音嗤疯,去河邊找鬼冤今。 笑死,一個(gè)胖子當(dāng)著我的面吹牛身弊,可吹牛的內(nèi)容都是我干的辟汰。 我是一名探鬼主播列敲,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼阱佛,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了戴而?” 一聲冷哼從身側(cè)響起凑术,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎所意,沒想到半個(gè)月后淮逊,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扶踊,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年泄鹏,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片秧耗。...
    茶點(diǎn)故事閱讀 40,021評論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡备籽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出分井,到底是詐尸還是另有隱情车猬,我是刑警寧澤,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布尺锚,位于F島的核電站珠闰,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏瘫辩。R本人自食惡果不足惜伏嗜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望伐厌。 院中可真熱鬧承绸,春花似錦、人聲如沸弧械。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽刃唐。三九已至羞迷,卻和暖如春界轩,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背衔瓮。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工浊猾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人热鞍。 一個(gè)月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓葫慎,卻偏偏與公主長得像,于是被迫代替她去往敵國和親薇宠。 傳聞我的和親對象是個(gè)殘疾皇子偷办,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,974評論 2 355

推薦閱讀更多精彩內(nèi)容