scrapy xpath選擇文本中有空格和回車導致用//text()提取不到想要的文本?完美解決!!


用scrapy框架做了一個簡單的爬蟲。算是練手。需求:爬取博客園新聞的標題、簡要、發布日期。

打開cmd, 輸入命令:
<code>scrapy shell https://news.cnblogs.com
view(response)</code>

查看元素所在位置。發現title位於h2 class="news_entry"下的a標簽里,如:

可以用css很容易的提取。response.xpath('h2.news_entry a::text').extract_first()

發布日期位於<span class="gray">標簽內,如:

用css也很容易提取。response.css('span.gray::text').extract_first()

 

但是,提取摘要的時候遇到了一個坑。估計是返爬的一個手法?位於<div class="entry_summary"標簽里。如下圖所示:

 

貌似很簡單提取,實際上是一個坑。先說一下剛開始的思路。
response.xpath('.//div[@class="entry_summary"]//text()').extract_first()
得到結果如下:

'\n                  '

.extract_first()的作用是每次提取第一個,放在循環里。這樣可以用yield函數遍歷。我們先用.extract()提取所有的內容,得到了一個列表。也可以不加.extract(),得到一個原始的xpath元素。如下:

發現了問題所在://text()方法是可以提取所有的文本,但是結果是一個列表,不適合做去除空格的進一步動作。而且,空格回車和文本本來應該是一個整體,但是結果卻分開了,以至於用.extract_first()提取到的是空格回車。

網上搜索答案,有人用string()方法可以跨標簽得到文本。用了一下,並沒有什么作用。而且,不能遍歷,只能得到第一個元素。也就是<code>'\n '</code>

貌似無解了?我又繼續網上搜索答案,路人甲的一篇文章給我了思路。他在文章里說,盡量用contains(.),而不是//text()。因為前者會把空格回車和文字作為一個整體提取,屬於模糊查詢,從而可以結合string()方法來獲得文本,也可以結合.strip()去除多余的空格回車。而//text()得到的是一個列表。里面的元素分開了。

如下:
response.xpath('string(.//div[@class="entry_summary"][contains(.,text())])').extract_first().strip()


因為contains()屬於模糊查找,連HTML標簽內容也匹配在內了。所以用string方法去除標簽。然后用.strip()去除空格。

結果相當完美:

附上完整代碼:

import scrapy


class NewsSpider(scrapy.Spider):
    name = "newss"

    start_urls = ['https://news.cnblogs.com/']
    # MAX_DOWNLOAD_NUMB = 100

    def parse(self, response):
        for news in response.css('div.news_block'):
            title = news.css('h2.news_entry a::text').extract_first()
            summary = news.xpath('string(.//div[@class="entry_summary"][contains(.,text())])').extract_first().strip() #//*[@id="entry_665993"]/div[2]/div[1]/text()
            time = news.css('span.gray::text').extract_first()

            yield {
                'title':title,
                'summary':summary,
                'time':time,
            }

        next_url = response.css('div.pager a:last-of-type::attr(href)').extract_first()
        if next_url:
            next_url = response.urljoin(next_url)
            yield scrapy.Request(next_url,callback=self.parse)

 

執行scrapy crawl newss -o news.csv
得到所有的文章標題、摘要、發布時間列表。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM