我找到了这个链接:https : //search.roblox.com/catalog/json?Category=2&Subcategory=2&SortType=4&Direction=2
原文是:https : //www.roblox.com/catalog/?Category=2&Subcategory=2&SortType=4
我试图用 Python 抓取整个目录中所有商品的价格,但我似乎无法找到这些商品的价格。每当我转到下一页时,该 URL 都不会更改。我试过检查网站本身,但我找不到任何东西。
第一个 URL 以某种方式可抓取,我在论坛上随机找到它。用户是如何在那里获取所有这些文本数据的?
注意:我知道该网站是为儿童设计的,但我通过在那里销售限量版来赚钱。请不要做出严厉的判断。:)
您可以在不使用BeautifulSoup或Selenium- 您只需要的情况下抓取所有项目信息requests。话虽如此,这不是超级直截了当,所以我会尝试分解它:
当您访问一个 URL 时,您的浏览器会向外部资源发出许多请求。这些资源托管在服务器上(或者,现在,托管在几个不同的服务器上),它们构成了浏览器正确呈现网页所需的所有文件/数据。举几个例子,这些资源可以是图片、图标、脚本、HTML文件、CSS文件、字体、音频等。仅供参考,www.google.com我的浏览器加载对各种资源一共36次请求。
您请求的第一个资源将始终是实际的网页本身,因此是一个类似 HTML 的文件。然后浏览器通过查看该 HTML 来确定它需要向哪些其他资源发出请求。
例如,假设网页包含一个包含我们要抓取的数据的表格。我们应该问自己的第一件事是“那个表格是如何出现在那个页面上的?”。我的意思是,用元素/html 标签填充网页的方式有多种。这是一种这样的方式:
page.html
资源请求像这样抓取页面时,使用BeautifulSoup是标准程序。您知道您要查找的数据已包含在 HTML 中,因此BeautifulSoup将能够看到它。
这是可以用元素填充网页的另一种方式:
page.html
资源请求当我说“稍后的时间点”时,对于使用实际浏览器查看页面的实际人类来说,该时间间隔可以忽略不计并且几乎不会引起注意。然而,服务器只为我们提供了一个“基本的”HTML。它只是一个空模板,它依靠脚本来填充它的表。该脚本向 Web API 发出请求,Web API 使用实际的表数据进行回复。所有这一切都需要有限的时间,并且只有在加载脚本资源后才能开始。
在抓取这样的页面时,您不能使用BeautifulSoup,因为它只会看到“基本”模板 HTML。这通常是您Selenium用来模拟真实浏览会话的地方。
要返回您的 roblox 页面,此页面是第二种类型。
我建议的方法(这是我最喜欢的方法,在我看来,应该是您总是首先尝试的方法),只涉及弄清楚 Web API 潜在脚本正在向哪些 Web API 发出请求,然后模仿请求来获取数据你要。这是我最喜欢的方法的原因是因为这些 Web API 通常提供 JSON,这很容易解析。它非常干净,因为您只需要一个第三方模块 ( requests)。
第一步是记录浏览器对资源的所有流量/请求。我将使用 Google Chrome,但其他现代浏览器可能具有类似的功能:
https://www.roblox.com/catalog/?Category=2&Subcategory=2&SortType=4)XMLHttpRequest或者
XHR资源是与服务器交互的对象。我们只想查看XHR资源,因为它们可能与 Web API 通信)单击列表中的项目之一。右侧应打开一个带有多个选项卡的面板。单击“标题”选项卡以查看请求 URL、请求和响应标题以及任何 cookie(查看“Cookies”选项卡以获得更漂亮的视图)。如果请求 URL 包含任何查询字符串参数,您还可以在此选项卡中以更漂亮的格式查看它们。这是它的样子(对不起,大图):
这个选项卡告诉我们关于模仿我们的请求我们想知道的一切。它告诉我们应该在哪里提出请求,以及应该如何制定我们的请求才能被接受。Web API 将拒绝格式错误的请求 - 并非所有 Web API 都关心相同的标头字段。例如,一些 Web API 非常关心“User-Agent”标头,但在我们的例子中,这个字段不是必需的。我知道这一点的唯一原因是因为我复制并粘贴了请求标头,直到 Web API 不再拒绝我的请求 - 在我的解决方案中,我将使用最低限度来发出有效请求。
但是,我们实际上需要弄清楚这些 XHR 对象中的哪一个负责与正确的 Web API 通信——即返回我们想要抓取的实际信息的 API。从列表中选择任何 XHR 对象,然后单击“预览”选项卡以查看 Web API 返回的数据的解析版本。假设是 Web API 将 JSON 返回给我们 - 在找到要查找的内容之前,您可能需要稍微展开和折叠树结构,但是一旦这样做,您就会知道这个 XHR 对象是要求我们需要模仿。我碰巧知道我们感兴趣的数据在名为“details”的 XHR 对象中。以下是“预览”选项卡中扩展 JSON 的部分内容:
如您所见,我们从这个 Web API ( https://catalog.roblox.com/v1/catalog/items/details)得到的响应包含我们想要抓取的所有有趣数据!
这就是事情变得有点深奥的地方,并且特定于这个特定的网页(到目前为止,您可以使用所有内容通过 Web API 从其他页面抓取内容)。以下是您访问时发生的情况https://www.roblox.com/catalog/?Category=2&Subcategory=2&SortType=4:
https://catalog.roblox.com/v1/search/items?category=Collectibles&limit=60&sortType=4&subcategory=Collectibles
(注意查询字符串参数)发出HTTP GET 请求(需要 cookie!),
响应是 JSON。它包含一个项目描述符列表,它看起来像这样:然后,一段时间后,另一个 XHR 对象(“详细信息”)向 Web API 发出 HTTP POST 请求https://catalog.roblox.com/v1/catalog/items/details(请参阅第一个和第二个屏幕截图)。如果此请求包含正确的 cookie 和前面提到的 CSRF/XSRF 令牌,则该请求仅被 Web API 接受。此外,此请求还需要一个包含我们要抓取其信息的资产 ID 的有效负载 - 未能提供此信息也会导致拒绝。
所以,这有点棘手。一个 XHR 对象的请求取决于另一个对象的响应。
所以,这是脚本。它首先创建一个requests.Session来跟踪 cookie。我们定义了一个字典params(它实际上只是我们的查询字符串)——您可以更改这些值以满足您的需要。它现在的编写方式是从“收藏品”类别中提取前 60 个项目。然后,我们使用正则表达式从 HTML 正文中获取 CSRF/XSRF 令牌。我们根据我们的 获取前 60 个项目的 id params,并生成最终 Web API 请求将接受的字典/有效负载。我们发出最终请求,创建一个项目列表(字典),并打印我们查询的第一个项目的键和值。
def get_csrf_token(session):
import re
url = "https://www.roblox.com/catalog/"
response = session.get(url)
response.raise_for_status()
token_pattern = "setToken\\('(?P<csrf_token>[^\\)]+)'\\)"
match = re.search(token_pattern, response.text)
assert match
return match.group("csrf_token")
def get_assets(session, params):
url = "https://catalog.roblox.com/v1/search/items"
response = session.get(url, params=params, headers={})
response.raise_for_status()
return {"items": [{**d, "key": f"{d['itemType']}_{d['id']}"} for d in response.json()["data"]]}
def get_items(session, csrf_token, assets):
import json
url = "https://catalog.roblox.com/v1/catalog/items/details"
headers = {
"Content-Type": "application/json;charset=UTF-8",
"X-CSRF-TOKEN": csrf_token
}
response = session.post(url, data=json.dumps(assets), headers=headers)
response.raise_for_status()
items = response.json()["data"]
return items
def main():
import requests
session = requests.Session()
params = {
"category": "Collectibles",
"limit": "60",
"sortType": "4",
"subcategory": "Collectibles"
}
csrf_token = get_csrf_token(session)
assets = get_assets(session, params)
items = get_items(session, csrf_token, assets)
first_item = items[0]
for key, value in first_item.items():
print(f"{key}: {value}")
return 0
if __name__ == "__main__":
import sys
sys.exit(main())
Run Code Online (Sandbox Code Playgroud)
输出:
id: 76692143
itemType: Asset
assetType: 8
name: Chaos Canyon Sugar Egg
description: This highly collectible commemorative egg recalls that *other* classic ROBLOX level, the one that was never quite as popular as Crossroads.
productId: 11837951
genres: ['All']
itemStatus: []
itemRestrictions: ['Limited']
creatorType: User
creatorTargetId: 1
creatorName: ROBLOX
lowestPrice: 400
purchaseCount: 7714
favoriteCount: 2781
>>>
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
513 次 |
| 最近记录: |