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

使用snscrape爬取Twitter英文推文遇404(blocked)错误求解决

解决snscrape爬取Twitter时的404(blocked)错误

5天前用snscrape爬取指定用户英文推文完全正常,现在突然报404(blocked)错误,已经升级过snscrape库,问题依旧。要求不使用官方API,修复该错误以正常爬取。

原代码

import pandas as pd
import snscrape.modules.twitter as sntwitter
scrapping_link = "https://twitter.com/tim_cook"
mycnt = 10
csv_file = "E:/django project/mywebsite/static/multiple posts/scraped_tweets.csv"   
username = scrapping_link.split('/')[-1]  # 从URL提取用户名   
count = 0  # 已爬取推文计数器
tweets_data = []  # 存储推文的列表    
for tweet in sntwitter.TwitterUserScraper(username).get_items():
  if count >= int(mycnt):
    break   
  if tweet.lang == "en" and tweet.content:
    tweet_text = tweet.content
    tweets_data.append({"username": username, "text": tweet_text})
    count += 1
# 将推文数据转为DataFrame
df = pd.DataFrame(tweets_data, columns=["username", "text"])
# 保存为CSV文件
df.to_csv(index=False, encoding="utf-8")                 

错误信息

ERROR:snscrape.base:Error retrieving https://twitter.com/i/api/graphql/7jT5GT59P8IFjgxwqnEdQw/SearchTimeline?variables=%7B%22rawQuery%22%3A%22from%3Atim_cook%22%2C%22count%22%3A20%2C%22product%22%3A%22Latest%22%2C%22withDownvotePerspective%22%3Afalse%2C%22withReactionsMetadata%22%3Afalse%2C%22withReactionsPerspective%22%3Afalse%7D&features=%7B%22rweb_lists_timeline_redesign_enabled%22%3Afalse%2C%22blue_business_profile_image_shape_enabled%22%3Afalse%2C%22responsive_web_graphql_exclude_directive_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Afalse%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22vibe_api_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Afalse%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Afalse%2C%22interactive_text_enabled%22%3Atrue%2C%22responsive_web_text_conversations_enabled%22%3Afalse%2C%22longform_notetweets_rich_text_read_enabled%22%3Afalse%2C%22longform_notetweets_inline_media_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%2C%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%7D: blocked (404)
CRITICAL:snscrape.base:4 requests to https://twitter.com/i/api/graphql/7jT5GT59P8IFjgxwqnEdQw/SearchTimeline?variables=%7B%22rawQuery%22%3A%22from%3Atim_cook%22%2C%22count%22%3A20%2C%22product%22%3A%22Latest%22%2C%22withDownvotePerspective%22%3Afalse%2C%22withReactionsMetadata%22%3Afalse%2C%22withReactionsPerspective%22%3Afalse%7D&features=%7B%22rweb_lists_timeline_redesign_enabled%22%3Afalse%2C%22blue_business_profile_image_shape_enabled%22%3Afalse%2C%22responsive_web_graphql_exclude_directive_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Afalse%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22vibe_api_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Afalse%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Afalse%2C%22interactive_text_enabled%22%3Atrue%2C%22responsive_web_text_conversations_enabled%22%3Afalse%2C%22longform_notetweets_rich_text_read_enabled%22%3Afalse%2C%22longform_notetweets_inline_media_enabled%22%3Afalse%2C%22responsive_web_enhance_cards_enabled%22%3Afalse%2C%22responsive_web_twitter_blue_verified_badge_is_enabled%22%3Atrue%7D failed, giving up.
CRITICAL:snscrape.base:Errors: blocked (404), blocked (404), blocked (404), blocked (404)
---------------------------------------------------------------------------
ScraperException                          Traceback (most recent call last)
<ipython-input-25-a22aa37f9c43> in <cell line: 9>()
      7 count = 0  # Counter for the number of scraped tweets
      8 tweets_data = []  # List to store the tweets
----> 9 for tweet in sntwitter.TwitterUserScraper(username).get_items():
     10   if count >= int(mycnt):
     11     break

5 frames
/usr/local/lib/python3.10/dist-packages/snscrape/base.py in _request(self, method, url, params, data, headers, timeout, responseOkCallback, allowRedirects, proxies)
    269                         _logger.fatal(msg)
    270                         _logger.fatal(f'Errors: {", ".join(errors)}')
--> 271                         raise ScraperException(msg)
    272                 raise RuntimeError('Reached unreachable code')
    273 

ScraperException: 4 requests to https://twitter.com/i/api/graphql/7jT5GT59P8IFjgxwqnEdQw/SearchTimeline?variables=%7B%22rawQuery%22%3A%22from%3Atim_cook%22%2C%22count%22%3A20%2C%22product%22%3A%22Latest%22%2C%22withDownvotePerspective%22%3Afalse%2C%22withReactionsMetadata%22%3Afalse%2C%22withReactionsPerspective%22%3Afalse%7D&features=%7B%22rweb_lists_timeline_redesign_enabled%22%3Afalse%2C%22blue_business_profile_image_shape_enabled%22%3Afalse%2C%22responsive_web_graphql_exclude_directive_enabled%22%3Atrue%2C%22verified_phone_label_enabled%22%3Afalse%2C%22creator_subscriptions_tweet_preview_api_enabled%22%3Afalse%2C%22responsive_web_graphql_timeline_navigation_enabled%22%3Atrue%2C%22responsive_web_graphql_skip_user_profile_image_extensions_enabled%22%3Afalse%2C%22tweetypie_unmention_optimization_enabled%22%3Atrue%2C%22vibe_api_enabled%22%3Atrue%2C%22responsive_web_edit_tweet_api_enabled%22%3Atrue%2C%22graphql_is_translatable_rweb_tweet_is_translatable_enabled%22%3Atrue%2C%22view_counts_everywhere_api_enabled%22%3Atrue%2C%22longform_notetweets_consumption_enabled%22%3Atrue%2C%22tweet_awards_web_tipping_enabled%22%3Afalse%2C%22freedom_of_speech_not_reach_fetch_enabled%22%3Afalse%2C%22standardized_nudges_misinfo%22%3Atrue%2C%22tweet_with_visibility_results_prefer_gql_limited_actions_policy_enabled%22%3Afalse%2C%22interactive_text_enabled%22%3Atrue%2C%22responsive_web_text_conversations_enabled%22%3Afalse%2C%22longform_notetweets_rich_text_read_enabled%22%3Afalse%2...

解决方案

方法1:添加请求头与代理

Twitter对无标识请求拦截加剧,给snscrape模拟浏览器请求头,搭配代理IP绕过限制:

import pandas as pd
import snscrape.modules.twitter as sntwitter

# 模拟Chrome浏览器请求头
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/118.0.0.0 Safari/537.36'
}

# 配置代理(替换为可用的代理地址)
proxies = {
    'http': 'http://your-proxy-address:port',
    'https': 'http://your-proxy-address:port'
}

scrapping_link = "https://twitter.com/tim_cook"
mycnt = 10
csv_file = "E:/django project/mywebsite/static/multiple posts/scraped_tweets.csv"   
username = scrapping_link.split('/')[-1]
count = 0
tweets_data = []

# 初始化Scraper并注入请求头和代理
scraper = sntwitter.TwitterUserScraper(username)
scraper._headers = headers
scraper._proxies = proxies

for tweet in scraper.get_items():
    if count >= int(mycnt):
        break
    if tweet.lang == "en" and tweet.content:
        tweets_data.append({"username": username, "text": tweet.content})
        count += 1

df = pd.DataFrame(tweets_data, columns=["username", "text"])
df.to_csv(csv_file, index=False, encoding="utf-8")

方法2:改用TwitterSearchScraper

通过搜索语法直接限定用户和语言,绕过用户时间线API的限制:

import pandas as pd
import snscrape.modules.twitter as sntwitter

scrapping_link = "https://twitter.com/tim_cook"
mycnt = 10
csv_file = "E:/django project/mywebsite/static/multiple posts/scraped_tweets.csv"   
username = scrapping_link.split('/')[-1]
count = 0
tweets_data = []

# 搜索语法:限定用户+英文推文
search_query = f"from:{username} lang:en"

for tweet in sntwitter.TwitterSearchScraper(search_query).get_items():
    if count >= int(mycnt):
        break
    if tweet.content:
        tweets_data.append({"username": username, "text": tweet.content})
        count += 1

df = pd.DataFrame(tweets_data, columns=["username", "text"])
df.to_csv(csv_file, index=False, encoding="utf-8")

方法3:安装snscrape开发版本

稳定版可能未适配Twitter最新API,安装开发分支版本:

pip uninstall -y snscrape
pip install git+https://github.com/JustAnotherArchivist/snscrape.git

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 16:37:04