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