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

使用Python 3.7的BeautifulSoup爬取WSJ文章无结果求排查

解决WSJ付费文章爬取无结果问题

我帮你排查了代码和WSJ的爬取逻辑,发现几个关键问题导致你没拿到结果,下面一步步给你分析和修正方案:

一、为啥代码没输出?核心问题拆解

1. 反爬拦截:缺失关键请求头

WSJ对爬虫的检测非常严格,requests.get()默认的请求头太“素”了,很容易被识别成机器人。哪怕你有付费订阅,请求里没带登录后的Cookie和真实浏览器的User-Agent,服务器只会返回未登录的页面或者空内容,自然爬不到文章。

2. CSS选择器完全失效

你用的那些选择器(比如.items.hedSumm li > a)应该是很久以前的了,WSJ的页面结构早就更新了。现在搜索结果页的文章链接、文章页的日期/标签/标题选择器都变了,旧选择器找不到任何元素,循环根本没执行,所以啥输出都没有。

3. 异常处理太“沉默”

你的代码只捕获了请求异常,但没处理“选择器找不到元素”这类错误(比如date[0].text如果date是空列表,会直接抛出IndexError),不过你说没报错,大概率是搜索页的选择器没找到任何item,外层循环直接跳过了,连错误都没机会抛。

二、具体修正步骤

1. 必须添加自定义请求头

打开浏览器,登录WSJ后,按F12打开开发者工具,在「网络」标签里找任意一个WSJ的请求,复制它的User-Agent和Cookie,加到你的代码里:

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
    'Cookie': '这里粘贴你浏览器里的Cookie字符串'
}

之后所有requests.get()都要带上这个headers参数,比如requests.get(url.format(page), headers=headers)。

2. 更新CSS选择器

打开WSJ的搜索页,用浏览器开发者工具(F12)查看当前元素结构,替换旧选择器:

  • 搜索结果页的文章链接:现在可以用div.search-results__item a[data-testid="search-result-item"](如果不对,自己在页面上右键检查元素确认)
  • 文章页日期:time[data-testid="timestamp"]
  • 文章标签:a.article-breadCrumb__link
  • 文章标题:h1[data-testid="article-heading"]
  • 文章内容:div.article-content p

3. 完善调试和异常处理

在代码里加一些打印信息,比如当前爬取的页码、找到的文章数量,方便你排查问题;同时捕获更多异常,避免程序悄悄崩溃:

print(f"正在爬取第 {page} 页...")
items = soup.select("你的新选择器")
print(f"找到 {len(items)} 篇文章")
if not items:
    print("未找到文章,可能选择器失效或被反爬")

三、修正后的完整代码

import time
import requests
from bs4 import BeautifulSoup

# 替换成你自己的Cookie和User-Agent
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Safari/537.36',
    'Cookie': '这里粘贴浏览器中WSJ登录后的Cookie'
}

url = 'https://www.wsj.com/search/term.html?KEYWORDS=cybersecurity&min-date=2018/04/01&max-date=2019/03/31' \
    '&isAdvanced=true&daysback=90d&andor=AND&sort=date-desc&source=wsjarticle,wsjpro&page={}'
pages = 32

for page in range(1, pages+1):
    print(f"===== 开始爬取第 {page} 页 =====")
    try:
        res = requests.get(url.format(page), headers=headers)
        res.raise_for_status()  # 检查请求是否成功(比如403、500错误)
        soup = BeautifulSoup(res.text, "lxml")
        
        # 更新为当前有效的文章链接选择器,需自行验证
        items = soup.select('div.search-results__item a[data-testid="search-result-item"]')
        print(f"找到 {len(items)} 条文章链接")
        
        for idx, item in enumerate(items):
            _href = item.get("href")
            if not _href.startswith('http'):
                _href = "https://www.wsj.com" + _href
            
            print(f"正在爬取第 {page} 页第 {idx+1} 篇文章: {_href}")
            try:
                resp = requests.get(_href, headers=headers)
                resp.raise_for_status()
                sauce = BeautifulSoup(resp.text, "lxml")
                
                # 提取日期,处理找不到元素的情况
                date_elem = sauce.select_one('time[data-testid="timestamp"]')
                date = date_elem.text.strip() if date_elem else "日期未知"
                
                # 提取标签
                tag_elem = sauce.select_one('a.article-breadCrumb__link')
                tag = tag_elem.text.strip() if tag_elem else "标签未知"
                
                # 提取标题
                title_elem = sauce.select_one('h1[data-testid="article-heading"]')
                title = title_elem.text.strip() if title_elem else "标题未知"
                
                # 提取内容
                content_elems = sauce.select('div.article-content p')
                content = '\n'.join([elem.text.strip() for elem in content_elems]) if content_elems else "内容为空"
                
                print(f'{date}\n{tag}\n{title}\n{content}\n{"-"*50}')
                
            except Exception as e:
                print(f"爬取文章失败: {str(e)}")
                continue
            
            time.sleep(2)  # 降低单页内的请求频率
            
    except Exception as e:
        print(f"爬取第 {page} 页失败: {str(e)}")
    
    time.sleep(3)  # 页面间的间隔时间

四、额外注意事项

  • Cookie会过期:过一段时间后,Cookie失效了要重新从浏览器复制。
  • 控制请求频率:不要把sleep时间设得太短,WSJ会封IP,建议每页间隔3-5秒,每篇文章间隔2-3秒。
  • 定期检查选择器:WSJ经常更新页面结构,爬取前一定要用开发者工具确认选择器是否有效。
  • 合规性:爬取付费内容要遵守WSJ的用户协议,不要商用或过度爬取。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:22:24