如何通过Python Jupyter Notebook爬取单条推特的所有回复
你运行代码后得到如下输出:
Empty DataFrame
Columns: [Date of Tweet, Replying to, Tweet]
Index: []
问题根因
返回空结果是以下几个逻辑错误导致的:
- 筛选条件完全不匹配:你遍历节点时要求
div标签带href=True属性,但div是块级布局标签,原生不存在href属性,该筛选条件直接匹配不到任何有效节点,循环体从未执行。另外你选用的css-1dbjc4n是Twitter全站通用布局类,会匹配到数百个无关DOM节点,并非回复专属容器。 - 未等待动态渲染完成:Twitter是前端动态渲染的单页应用,打开链接后需要等待接口返回、DOM绘制完成才能获取到内容,你打开页面后立刻抓取源码,此时回复区域还未加载。
- 未处理懒加载机制:Twitter回复采用滚动触发的懒加载逻辑,不触发滚动操作只会加载首屏的少量回复,无法获取全量340条数据。
- 定位方式稳定性差:你抓取的带
r-前缀的class是Tailwind编译生成的动态类,Twitter每次前端发版都可能变更,用这类属性定位很容易失效。 - 缺少校验与过滤逻辑:没有判断子节点是否存在就直接调用
.text会触发空指针报错,也没有加过滤规则排除楼中楼里回复其他用户的内容。
修正实现
以下代码可直接在Jupyter Notebook中运行,适配你的采集需求:
- 前置依赖安装:先在Notebook中执行
!pip install selenium beautifulsoup4 pandas openpyxl安装所需包,提前配置好ChromeDriver,保证和本地Chrome大版本一致。 - 代码逻辑说明:用显式等待替代固定等待,自动滚动加载全量回复,用稳定的
data-testid属性做元素定位,自动筛选直接回复@BBCWorld的内容,最终导出为Excel文件。
import time from selenium import webdriver from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from bs4 import BeautifulSoup import pandas as pd # 初始化浏览器 driver = webdriver.Chrome() driver.maximize_window() target_url = "https://twitter.com/BBCWorld/status/1534777385249390593" driver.get(target_url) # 等待首屏内容加载 wait = WebDriverWait(driver, 20) wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '[data-testid="tweet"]'))) # 自动滚动加载所有回复 last_height = driver.execute_script("return document.body.scrollHeight") scroll_pause_time = 2 while True: # 滚动到底部 driver.execute_script("window.scrollTo(0, document.body.scrollHeight);") time.sleep(scroll_pause_time) # 计算新的页面高度,判断是否加载完成 new_height = driver.execute_script("return document.body.scrollHeight") if new_height == last_height: break last_height = new_height # 全量内容加载完成后解析 content = driver.page_source soup = BeautifulSoup(content, "html.parser") all_tweets = soup.find_all(attrs={"data-testid": "tweet"}) dates = [] replying_to = [] tweet_texts = [] for tweet in all_tweets: # 跳过原推文,只处理回复 is_original = tweet.find("a", href="/BBCWorld/status/1534777385249390593") if is_original: continue # 提取回复日期 time_tag = tweet.find("time") if not time_tag: continue reply_date = time_tag.get("datetime", "") # 提取回复对象,筛选仅直接回复BBC的内容 reply_target_tag = tweet.find(string=lambda text: text and "Replying to" in text) if not reply_target_tag: continue reply_target = reply_target_tag.find_parent().find_all("span")[-1].text if reply_target != "@BBCWorld": continue # 提取回复文本 text_tag = tweet.find(attrs={"data-testid": "tweetText"}) if not text_tag: continue reply_content = text_tag.text.replace("\n", " ").strip() dates.append(reply_date) replying_to.append(reply_target) tweet_texts.append(reply_content) # 关闭浏览器 driver.quit() # 导出为Excel df = pd.DataFrame({ "回复日期": dates, "回复对象": replying_to, "回复文本": tweet_texts }) df.to_excel("BBC推文回复.xlsx", index=False) print(f"共采集到{len(df)}条直接回复BBC的有效内容") print(df.head())
注意事项
- 如果运行时遇到登录拦截,可以在初始化浏览器后手动扫码登录Twitter,再继续执行后续逻辑,未登录状态下Twitter会限制内容展示。
- 滚动等待时间可以根据你的网络情况调整,网络较差时可以把
scroll_pause_time调大到3-5秒,避免漏加载内容。 - 不要频繁短时间大量爬取,会触发Twitter的反爬限制,导致IP被临时封禁。
内容的提问来源于stack exchange,提问作者M_B
相关产品推荐
相关产品推荐

