Spider-scrapy 中的 xpath 語法與調試

把setting中的機器人過濾設爲Falsecss

ROBOTSTXT_OBEY = False 

1 語法

artcilehtml

選取全部子節點python

/article程序員

選取根元素 artileshell

article/a數組

選取全部屬於artile的子元素中的a元素dom

//divscrapy

選取全部 div 元素(無論出如今文檔任何位置)ide

article//div函數

選取全部屬於artile元素的後代的 div 元素,無論出如今 article 之下的任何位置

//@class

選取全部名爲 class 的屬性。

/article/div[1]

選取屬於article子元素的第一個div元素

/article/div[last()]

選取屬於article子元素的最後一個div元素

/article/div[last()-1]

選取屬於article子元素的倒數第二個div元素

//div[@lang]

選取全部擁有lang屬性的div元素

//div[@lang='eng']

選取全部lang屬性爲eng的div元素

debug

1 pycharm

id是全局惟一的

re_selector2 = response.xpath('//*[@id="post-110595"]/div[1]/h1/text()')

若是class='entry-header'是全局惟一,能夠比上面少一層節點。

re_selector3 = response.xpath("//div[@class='entry-header']/h1/text()")

2 scrapy shell

對某一頁http://blog.jobbole.com/110595/ 進行debug

scrapy shell http://blog.jobbole.com/110595/

獲得response對象。

能夠用dir(response)看屬性和方法。用type(response)看類型。

>>> title = response.xpath("//div[@class='entry-header']/h1/text()")
>>> title
[<Selector xpath="//div[@class='entry-header']/h1/text()" data='爲何該和程序員約會?我有 20 個理由'>]

如何獲取title中的數據?使用extract()方法,獲得數組,再用序號能夠獲得具體值。

>>> title.extract()
['爲何該和程序員約會?我有 20 個理由']
>>> title.extract()[0]
'爲何該和程序員約會?我有 20 個理由'

不直接extra()是由於title 能夠保持爲selector對象。

獲取時間,把裏面的文本用text()獲取出來。再用strip()默認出去默認字符。

>>> create_date = response.xpath("//p[@class='entry-meta-hide-on-mobile']/text()").extract()[0]
>>> create_date
'\r\n\r\n            2017/03/18 ·  '
>>> create_date = create_date.strip()
>>> create_date
'2017/03/18 ·'
>>> a = create_date.replace("·","").strip()
>>> a
'2017/03/18'
>>> b = create_date.strip("·")
>>> b
'2017/03/18 '
>>> b = create_date.strip("·").strip()
>>> b
'2017/03/18'

只取多個class屬性中的一個,用xpath的函數 contains。

好比要選取span,可是class有多項。而只想要其中的vote-post-up,能夠用xpath的contains。

<span data-post-id="110595" class=" btn-bluet-bigger href-style vote-post-up   register-user-only "><i class="fa  fa-thumbs-o-up"></i> <h10 id="110595votetotal">2</h10> 贊</span>
>>> response.xpath("//span[contains(@class, 'vote-post-up')]")
[<Selector xpath="//span[contains(@class, 'vote-post-up')]" data='<span data-post-id="110595" class=" btn-'>]

列表生成式

過濾評論

>>> response.xpath("//p[@class='entry-meta-hide-on-mobile']/a/text()").extract()[0:]
['其餘', ' 7 評論 ', '約會']
>>> [element for element in tag_list if not element.strip().endswith("評論")]
['其餘', '約會']
tag_list = [ element for element in tag_list if not element.strip().endswith("評論") ]
tags = ",".join(tag_list)

以什麼結尾必定是 .endswith()

extract_first()

對數組取第0個、第1個的時候,若是數組爲空,則可能拋出異常。

可是若是用extract_first(),不用作異常處理,結果爲空或者None。

def extract_first(self, default=None):
    for x in self:
        return x.extract()
    else:
        return default

相似於字典的get方法,提取不到就返回空。

最終 jobbole.py

# -*- coding: utf-8 -*-
import re
import scrapy


class JobboleSpider(scrapy.Spider):
    name = "jobbole"
    allowed_domains = ["blog.jobbole.com"]
    start_urls = ['http://blog.jobbole.com/110595/']

    def parse(self, response):
        # re_selector1 = response.xpath("/html/body/div[1]/div[3]/div[1]/div[1]/h1")
        # re_selector2 = response.xpath('//*[@id="post-110595"]/div[1]/h1/text()')
        # re_selector3 = response.xpath("//div[@class='entry-header']/h1/text()")
        title  = response.xpath("//div[@class='entry-header']/h1/text()").extract()[0]
        create_date = response.xpath("//p[@class='entry-meta-hide-on-mobile']/text()").extract()[0].strip().replace("·","").strip()
        praise_nums = response.xpath("//span[contains(@class, 'vote-post-up')]//h10/text()").extract()[0]
        fav_nums = response.xpath("//span[contains(@class, 'bookmark-btn')]/text()").extract()[0]
        match_re = re.match(".*?(\d+).*", fav_nums)
        if match_re:
            fav_nums = match_re.group(1)
        comment_nums = response.xpath("//a[@href='#article-comment']/span/text()").extract()[0]
        match_re = re.match(".*?(\d+).*", comment_nums)
        if match_re:
            comment_nums = match_re.group(1)

        content = response.xpath("//div[@class='entry']").extract()[0]
        tag_list = response.xpath("//p[@class='entry-meta-hide-on-mobile']/a/text()").extract()
        tag_list = [ element for element in tag_list if not element.strip().endswith("評論") ]
        tags = ",".join(tag_list)


        # 經過css選擇器提取字段
        title = response.css(".entry-header h1::text").extract()[0]
        create_date = response.css(".entry-meta-hide-on-mobile::text").extract()[0].strip().replace("·","").strip()
        praise_nums = response.css("div.post-adds h10::text").extract()[0]

        # fav_nums = response.css("span[class*='bookmark-btn']::text").extract()[0]
        fav_nums = response.css(".bookmark-btn::text").extract()[0]
        match_re = re.match(".*?(\d+).*", fav_nums)
        if match_re:
            fav_nums = match_re.group(1)

        # comment_nums = response.css("span[class='btn-bluet-bigger href-style hide-on-480']::text").extract()[0]
        comment_nums = response.css("a[href='#article-comment'] span::text").extract_first()
        match_re = re.match(".*?(\d+).*", comment_nums)
        if match_re:
            comment_nums = match_re.group(1)
        content = response.css(".entry").extract()[0]
        tag_list = response.css("p.entry-meta-hide-on-mobile a::text").extract()
        tag_list = [element for element in tag_list if not element.strip().endswith("評論")]
        tags = ",".join(tag_list)
        pass
相關文章
相關標籤/搜索