使用 Python 进行 Twitter 抓取

Twitter scraping using Python

我一直在为 reverse-enginner Twitter 的应用开发一个项目,使用非官方 API 和 Python 从 Twitter 上抓取 public 帖子。 (我想创建一个“替代”应用程序,它只是一个可以搜索用户并获取其帖子的本地主机)

我一直在搜索和阅读与 REST、AJAX 和 python 模块请求、requests-html、BeautifulSoup 等相关的所有内容。

我在 devtools 上查看 Twitter 时(例如在 Marvel 的个人资料页面上)可以看到,(通过 POST 和 GET)发送的唯一相关请求如下:client_event.json 和UserTweets?变量=...。 我知道这些是通过清理网络选项卡收到的相关消息,只有当我向下滚动并加载新推文时才进行记录 - 这些是唯一出现的消息,它们不是随机视频(我使用 -video - 清理搜索init -csp_report -config -ondemand -like -pageview -recommendations -prefetch -jot -key_live_kn -svg -jpg -jpeg -png -ico -analytics -loader -sharedCore -Hebrew).

我是这个领域的新手,所以我可能做错了什么。我可以在 UserTweets 上看到我正在寻找的响应 - 一个漂亮的 JSON 包含我需要的所有数据 - 但无论我尝试了多少,我都无法访问它。

我尝试了不同的模块和不同的 headers,但我什么也没得到。我不想使用 Selenium,因为它很烦人,而且我知道我需要的数据存储在哪里。

我一直在尝试将 GET 请求发送至: https://twitter.com/i/api/graphql/vamMfA41UoKXUmppa9PhSw/UserTweets?variables=%7B%22userId%22%3A%2215687962%22%2C%22count%22%3A20%2C%22cursor%22%3A%22HBaIgLLN%2BKGEryYAAA%3D%3D%22%2C%22withHighlightedLabel%22%3Atrue%2C%22withTweetQuoteCount%22%3Atrue%2C%22includePromotedContent%22%3Atrue%2C%22withTweetResult%22%3Afalse%2C%22withUserResults%22%3Afalse%2C%22withVoice%22%3Afalse%2C%22withNonLegacyCard%22%3Atrue%7D

通过做:

from requests_html import HTMLSession
from bs4 import BeautifulSoup

response = session.get('https://twitter.com/i/api/graphql/vamMfA41UoKXUmppa9PhSw/UserTweets?variables=%7B%22userId%22%3A%2215687962%22%2C%22count%22%3A20%2C%22cursor%22%3A%22HBaIgLLN%2BKGEryYAAA%3D%3D%22%2C%22withHighlightedLabel%22%3Atrue%2C%22withTweetQuoteCount%22%3Atrue%2C%22includePromotedContent%22%3Atrue%2C%22withTweetResult%22%3Afalse%2C%22withUserResults%22%3Afalse%2C%22withVoice%22%3Afalse%2C%22withNonLegacyCard%22%3Atrue%7D')
response.html.render()
s = BeautifulSoup(response.html.html, 'lxml')

但是我得到了一个 HTML 脚本,要么说 Chromium 不受支持,要么只是一个没有 javascript 更新 DOM.

的静态页面

感谢所有帮助。

谢谢

P.S 为了安全起见,我在 reverseengineering.stackexchange 上发布了同样的问题(overflow 有更合适的标签 :-))

我刚刚尝试过相同的方法,但使用的是 requests,而不是 requests_html 模块。我可以获得所有网站内容,但我不会称之为“美丽”。

此外,现在我被禁止在不登录的情况下访问该站点。 这是我的小例子。 请改用官方 Twitter API。

我也认为在尝试使用此脚本后我可能会被阻止。我只试过2次。

import requests
import bs4

def example():
    result = requests.get("https://twitter.com/childrightscnct")
    soup = bs4.BeautifulSoup(result.text, "lxml")
    print(soup)

if __name__ == '__main__':
    example()

要select任何带bs4的元素,使用

some_text = soup.select('locator').getText()

我找到了一个抓取 Twitter 的工具,它在 Github 上有很多星 https://github.com/twintproject/twint 我自己没有尝试过,希望它是合法的。

@TripleS,如何从 __INITIAL_STATE__ 中提取 json 数据并将其写入文本文件的示例。

import requests
import re
import json
from contextlib import suppress

# get page
result = requests.get('https://twitter.com/ThePSF')


# Extract json from "window.__INITIAL_STATE__={....};
json_string = re.search(r"window.__INITIAL_STATE__\s?=\s?(\{.*?\});", result.text).group(1)

# convert text string to structured json data
twitter_json = json.loads(json_string)

# Save structured json data to a text file that may help
# you to orient yourself and possible pick some parts you
# are interested in (if there are any)
with open('twitter_json_data.txt', 'w') as outfile:
    outfile.write(json.dumps(twitter_json, indent=4, sort_keys=True))

在深入研究实际代码之前,我首先要开始构建正确的 Twitter 请求。我会使用专注于 REST 和 API 的第 3 方工具,例如 Postman 来构建和测试所需的请求——然后才会编写实际代码。

从你的问题看来,你将使用一个开放的 API 推特,所以这意味着你只需要在你的请求中发送 x-guest-token 和基本的 Bearer 授权 headers.

  • Bearer 是静态的 - 您可以浏览到 Twitter 和 copy/paste 它来自开发工具网络监视器。
  • 要获得 x-guest-token 你需要一些动态的东西,因为它已经过期了,我建议向 Twitter 发送一个 curl 请求,从那里解析令牌并将其放入你的header 在发送请求之前。您可以在以下内容中看到非常相似的内容:Python 使用 python 下载推特视频(不使用推特 api) .

完成以上两项后,在 Postman 中构建所需的 GET 请求并测试是否返回正确的响应。只有当你在 Postman 中完成所有工作后 - 用 Python 或任何其他语言编写相同的内容**

**您可以使用 Postman 片段自动生成许多编程语言所需的代码。

您缺少的是发出请求所需的持有者和来宾令牌。如果我只是用 curl 击中了你的端点而没有 headers 我没有得到任何回应。但是,如果我为不记名令牌和来宾令牌添加 headers,那么我会得到您正在寻找的 json:

curl https://twitter.com/i/api/graphql/vamMfA41UoKXUmppa9PhSw/UserTweets?variables=%7B%22userId%22%3A%2215687962%22%2C%22count%22%3A20%2C%22cursor%22%3A%22HBaIgLLN%2BKGEryYAAA%3D%3D%22%2C%22withHighlightedLabel%22%3Atrue%2C%22withTweetQuoteCount%22%3Atrue%2C%22includePromotedContent%22%3Atrue%2C%22withTweetResult%22%3Afalse%2C%22withUserResults%22%3Afalse%2C%22withVoice%22%3Afalse%2C%22withNonLegacyCard%22%3Atrue%7D -H 'authorization: Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA'' -H 'x-guest-token: 1452696114205847552'

您可以像这样获取不记名令牌(可能不会经常过期)和访客令牌(我认为确实会过期):

  1. twitter 的 html link 你去 link 一个名为 main.some 的文件随机 numbers.js.在那个 javascript 文件中是不记名令牌。您可以认出这是因为以很多 A 开头的长字符串。
  2. 获取不记名令牌并使用不记名令牌作为授权调用https://api.twitter.com/1.1/guest/activate.jsonheader

curl 'https://api.twitter.com/1.1/guest/activate.json' -X POST -H 'authorization: Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA'

在 python 中看起来像:

import requests
import json

url = "https://twitter.com/i/api/graphql/vamMfA41UoKXUmppa9PhSw/UserTweets?variables=%7B%22userId%22%3A%2215687962%22%2C%22count%22%3A20%2C%22cursor%22%3A%22HBaIgLLN%2BKGEryYAAA%3D%3D%22%2C%22withHighlightedLabel%22%3Atrue%2C%22withTweetQuoteCount%22%3Atrue%2C%22includePromotedContent%22%3Atrue%2C%22withTweetResult%22%3Afalse%2C%22withUserResults%22%3Afalse%2C%22withVoice%22%3Afalse%2C%22withNonLegacyCard%22%3Atrue%7D"
headers = {"authorization": "Bearer AAAAAAAAAAAAAAAAAAAAANRILgAAAAAAnNwIzUejRCOuH5E6I8xnZz4puTs%3D1Zv7ttfk8LF81IUq16cHjhLTvJu4FA33AGWWjCpTnA", "x-guest-token": "1452696114205847552"}
resp = requests.get(url, headers=headers)
j = json.loads(resp.text)

现在,那个变量 j 保存着你美丽的 json。一个警告,有时返回的响应可能太大,以至于似乎无法放入单个响应中。如果发生这种情况,您会注意到 resp.text 无效 json,而只是 json 的大型博客的一部分。要解决此问题,您只需要调整请求以使用“stream=True”并在尝试将其解析为 json.

之前流出整个响应。