You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用Scrapy爬取网站新闻索引页的完整文章正文

问题原因
  • 你写的text': news.css('p.categoryArticle__excerpt::text').get()选择器抓不到文本,是因为你贴的HTML结构里,<p class="categoryArticle__excerpt"></p>是空标签,后面那段预览文字是直接放在父容器div.categoryArticle__content下、和p标签平级的文本节点,根本不属于这个p标签的内容,自然选不到。
  • 就算你改选择器拿到了这段文字,也只是列表页展示的几十字截断摘要,不是完整新闻正文,要抓全文必须进单篇新闻的详情页。
  • 原代码还有两个隐藏bug:一是category字段的XPath用//开头是全局匹配,放在循环里每次都拿同一个值,完全没必要;二是下一页直接选a.num会匹配到所有数字页码按钮,容易重复爬取、跳错页甚至死循环。
调整方案

按Scrapy的跨页爬取逻辑改即可:

  1. 列表页循环里先提取已经能稳定拿到的发布时间、分类、标题,同时提取每条新闻对应的详情页链接
  2. 用response.follow跳转到详情页,把已经提取到的字段通过meta参数传递过去
  3. 新增详情页解析方法,定位详情页的正文容器,提取所有段落文本拼接成完整正文
  4. 修正下一页的选择规则,只匹配专门的“下一页”按钮,避免跳页错误
修正后可直接运行的代码
import scrapy

class CoalNewsFromOilPrice(scrapy.Spider):
    name = 'coalnews'
    start_urls = ['https://oilprice.com/Energy/Coal/']

    def parse(self, response):
        # 分类是列表页全局字段,循环外只取一次
        category = response.xpath('//h1[@class="categoryHeading"]/text()').get().replace('/', '').replace(' ','')
        for news in response.css('div.categoryArticle__content'):
            item = {
                'datetime': news.css('p.categoryArticle__meta::text').get(),
                'category': category,
                'title': news.css('h2.categoryArticle__title::text').get(),
            }
            # 提取详情页地址:标题h2的父节点a标签就是详情页入口
            detail_url = news.css('h2.categoryArticle__title').xpath('../@href').get()
            # 跳转详情页,传递已提取的元数据
            yield response.follow(
                detail_url,
                callback=self.parse_detail,
                meta={'item': item}
            )
        # 匹配下一页按钮,不存在则停止爬取
        next_page = response.css('a.pagination__next::attr(href)').get()
        if next_page:
            yield response.follow(next_page, callback=self.parse)

    def parse_detail(self, response):
        item = response.meta['item']
        # 提取正文所有段落,去空白后拼接
        content_paragraphs = response.css('div.article__content p::text').getall()
        item['text'] = '\n'.join([p.strip() for p in content_paragraphs if p.strip()])
        yield item
补充说明
  • 如果运行后发现正文抓空,打开浏览器F12检查下详情页正文容器的class名是否有变动,替换成最新的class选择器即可。
  • 如果你需要保留列表页的那段短摘要,可以在列表页的item里加一行'short_excerpt': news.xpath('./text()').getall()[-1].strip(),就能拿到那段游离在p标签外的预览文本。

内容的提问来源于stack exchange,提问作者yangyang

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 13:09:28