html - 从 Kickstarter 项目中抓取文本不会返回任何内容
问题描述
我正在尝试从 Kickstarter 项目网页中抓取项目的主要文本。我有以下代码适用于第一个 URL,但不适用于第二个和第三个 URL。我想知道是否可以轻松修复我的代码而无需使用其他包?
url = "https://www.kickstarter.com/projects/1365297844/kuhkubus-3d-escher-figures?ref=discovery_staff_picks_category_newest"
#url = "https://www.kickstarter.com/projects/clarissaredwine/swingby-a-voyager-gravity-puzzle?ref=discovery_staff_picks_category_newest"
#url = "https://www.kickstarter.com/projects/100389301/us-army-navy-marines-air-force-special-challenge-c?ref=category"
page = requests.get(url)
soup = BeautifulSoup(page.content, 'html.parser')
body_text = soup.find(class_='rte__content')
all_text = body_text.find_all('p')
for i in all_text:
print(i.get_text())
解决方案
这个网站使用了一个GraphQL API :
POST https://www.kickstarter.com/graph
我们可以使用它来获取站点数据,而不是为任何 URL(任何项目)抓取 html。此外,还有两个字段story
,risks
我们将提取它们。
这个 Graphql API 需要一个嵌入在meta
页面标签中的 csrf 令牌(任何页面都可以)。此外,我们需要使用请求会话存储 cookie,否则调用将失败。
以下是使用python简单使用 API 的示例:
import requests
from bs4 import BeautifulSoup
s = requests.Session()
r = s.get("https://www.kickstarter.com")
soup = BeautifulSoup(r.text, 'html.parser')
xcsrf = soup.find("meta", {"name": "csrf-token"})["content"]
query = """
query GetEndedToLive($slug: String!) {
project(slug: $slug) {
id
deadlineAt
showCtaToLiveProjects
state
description
url
__typename
}
}"""
r = s.post("https://www.kickstarter.com/graph",
headers= {
"x-csrf-token": xcsrf
},
json = {
"query": query,
"variables": {
"slug":"kuhkubus-3d-escher-figures"
}
})
print(r.json())
从您的第二个链接中,它显示了查询中的有趣字段。完整的查询如下:
query Campaign($slug: String!) {
project(slug: $slug) {
id
isSharingProjectBudget
risks
story(assetWidth: 680)
currency
spreadsheet {
displayMode
public
url
data {
name
value
phase
rowNum
__typename
}
dataLastUpdatedAt
__typename
}
environmentalCommitments {
id
commitmentCategory
description
__typename
}
__typename
}
}
我们只对 感兴趣,story
所以risks
我们将拥有:
query Campaign($slug: String!) {
project(slug: $slug) {
risks
story(assetWidth: 680)
}
}
请注意,我们需要作为 url 一部分的项目 slug,例如clarissaredwine/swingby-a-voyager-gravity-puzzle
,您的第二个 url 的 slug。
这是一个示例实现,它提取 slug,遍历 slug 并为每个 slug 调用 GraphQL 端点,它会打印每个 slug 的故事和风险:
import requests
from bs4 import BeautifulSoup
import re
urls = [
"https://www.kickstarter.com/projects/1365297844/kuhkubus-3d-escher-figures?ref=discovery_staff_picks_category_newest",
"https://www.kickstarter.com/projects/clarissaredwine/swingby-a-voyager-gravity-puzzle?ref=discovery_staff_picks_category_newest",
"https://www.kickstarter.com/projects/100389301/us-army-navy-marines-air-force-special-challenge-c?ref=category"
]
slugs = []
#extract slugs from url
for url in urls:
slugs.append(re.search('/projects/(.*)\?', url).group(1))
s = requests.Session()
r = s.get("https://www.kickstarter.com")
soup = BeautifulSoup(r.text, 'html.parser')
xcsrf = soup.find("meta", {"name": "csrf-token"})["content"]
query = """
query Campaign($slug: String!) {
project(slug: $slug) {
risks
story(assetWidth: 680)
}
}"""
for slug in slugs:
print(f"--------{slug}------")
r = s.post("https://www.kickstarter.com/graph",
headers= {
"x-csrf-token": xcsrf
},
json = {
"operationName":"Campaign",
"variables":{
"slug": slug
},
"query": query
})
result = r.json()
print("-------STORY--------")
story_html = result["data"]["project"]["story"]
soup = BeautifulSoup(story_html, 'html.parser')
for i in soup.find_all('p'):
print(i.get_text())
print("-------RISKS--------")
print(result["data"]["project"]["risks"])
我想如果你在这个网站上抓取其他内容,你可以将 graphQL 端点用于许多其他事情。但是,请注意,该 API 已禁用自省,因此您只能在站点上查找现有架构使用情况(您无法获取整个架构)
推荐阅读
- python - 在 Kivy 的 API 30 (Android 11) 中读取和写入文件
- jquery - 如何在数组中添加多个链接搜索条件
- c# - MoveWindow 和 SetWindowPos 都会导致不正确的窗口位置/大小
- javascript - 在 React 中使用 props 输入导出数组
- apache-kafka - 如何在 Kafka 中启动 mongodb 的工作连接器?
- angular - 我如何在 ngIf 条件 Angular 中使用函数
- vue.js - 为 VueJS 开发服务器启用 CORS
- reactjs - reactstrap中的边距和填充?
- c - 每次添加到目录时如何访问新文件?
- python-3.x - Python ciscoconfparse 查找关闭接口和整个接口块?