python - 循环浏览 Grand Comic Book 数据库中的 URL 列表
问题描述
我最近一直在尝试手动执行以下操作,我想知道是否有一种快速的自动化方法。我唯一的经验是在 Ubuntu 的终端中使用 python/python3,这就是为什么我希望在 python 中而不是其他的。
一些背景:网站 my.comics.org 是一个漫画书数据库,其中给定的问题有一个 URL 的形式https://my.comics.org/issue/#
,其中#
是一些数字。如果一个人登录到一个帐户,则会有一个“添加”按钮将问题添加到所选列表中。我正在尝试拼凑一个脚本,该脚本将循环遍历与数字范围相对应的 URL,并将每个问题添加到所选列表中。选择列表保存在浏览器中,因此不需要指定,因此只需单击按钮即可。检查“添加”按钮,html中有以下行
<input type="submit" name="confirm_selection" value="Add">`
我希望有足够的信息来告诉脚本单击哪个按钮。
我知道我可以使用 webbrowser 模块打开网页,但我不知道如何打开 URL,单击“添加”按钮,关闭选项卡,然后在给定范围内重复。
只是在试验,我在 python 命令行中尝试了类似的东西
import webbrowser
for i in range(1,5):
webbrowser.open('https://my.comics.org/issue/'+str(i))
这打开了一堆标签,但我遇到了几个错误,比如
Unable to open /var/lib/snapd/desktop/dconf/profile/user: Permission denied
我也不想同时打开所有选项卡,因为我想在一系列问题上运行脚本,比如 1000 个问题。有没有一种简单的方法可以做到这一点?谢谢。
解决方案
有一些空闲时间,所以我在 my.comics.org 上注册了一个帐户。
我不会为此使用该webbrowser
模块。相反,我会使用该requests
模块。使用requests
,您可以向网站发出 HTTP GET 和 POST 请求(以及其他一些请求)。这个想法是您创建一个请求有效负载并将其提交到所需的 URL,以便您可以或多或少地模仿您将在浏览器中执行的“操作”。最困难的部分是使您的请求格式正确,并知道在其中放入什么以便接收服务器接受它们。
这是我想出的代码(注意,我在几个地方使用了 f-strings,这是 Python 3.6 的一个特性。如果你没有 f-strings,你可以只做普通的旧字符串格式化):
def main():
import requests
login_url = "https://my.comics.org/accounts/login/"
client = requests.session()
# First, get the CSRF token.
client.get(login_url)
csrf_token = client.cookies["csrftoken"]
email = "YOUR EMAIL GOES HERE"
password = "YOUR PASSWORD GOES HERE"
credentials = {
"username": email,
"password": password,
"csrfmiddlewaretoken": csrf_token,
"next": "/"
}
headers = {
"User-Agent": "User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.169 Safari/537.36",
"Referer": login_url,
"Connection": "keep-alive",
"Host": "my.comics.org",
"Origin": "https://my.comics.org"
}
request = client.post(login_url, data=credentials, headers=headers)
# We should be logged in now.
# Here is where we can start adding the issues to our desired collection(s).
issue_numbers = [41485, 41486, 41487]
collection_id = "27402"
number_of_issues = len(issue_numbers)
for issue_index, issue_number in enumerate(issue_numbers):
issue_url = f"https://my.comics.org/issue/{issue_number}/add_to_collection/"
# Get the CSRF token again.
client.get(issue_url)
csrf_token = client.cookies["csrftoken"]
data = {
"csrfmiddlewaretoken": csrf_token,
"confirm_selection": "Add",
"collection_id": collection_id,
}
headers["Referer"] = issue_url
print(f"({issue_index+1}/{number_of_issues}) Adding issue# {issue_number} to collection# {collection_id}...")
request = client.post(issue_url, data=data, headers=headers)
print("All done!")
return 0
if __name__ == "__main__":
import sys
sys.exit(main())
一些注意事项:
第一步是创建一个请求会话,就像您的浏览器在您访问网站时如何为您创建一个会话一样。我们想做的下一件事是登录我们的帐户。为此,我们需要一个“用户名”(电子邮件)和密码。我们还需要一个叫做 CSRF 令牌的东西,它是服务器发送给您的一次性 cookie,用于唯一标识您的会话。我们设置的方法是创建一个字典,将“用户名”映射到您的电子邮件,将“密码”映射到您的密码等。我们几乎准备好提交我们的第一个 POST 请求,但您还必须提供一个标题到服务器,哪种描述您的客户端以及您来自哪里(服务器通常也希望看到这一点以确保您的请求是真实的)。
在我们的第一个 POST 请求之后,我们现在应该登录(注意,与 webbrowser 模块不同,这些都不会打开任何选项卡或浏览器实例。这一切都发生在幕后)。登录后,我们可以迭代我们有兴趣添加到我们的集合中的问题。
注意,对于我的 collection_id,我选择了值“27402”。您可能必须更改此值,因为这是我的集合的 ID(我为这个项目制作了一个“python 集合”)。我找出要添加到的集合的 ID 的方法是查看 HTML:
<form method="POST" action="/issue/41485/add_to_collection/">
<input type='hidden' name='csrfmiddlewaretoken' value='REDACTED, NORMALLY A BUNCH OF RANDOM CHARACTERS' />
<div>
<input type="submit" name="confirm_selection" value="Add">
this issue to your
<select name="collection_id">
<option value="27400" >Default have collection
<option value="27401" >Default want collection
<option value="27402" >python collection
</select>
</div>
</form>
请注意,我的 python 集合的“价值”。这是我们可以从“添加”按钮下的下拉窗口中选择的集合的 ID。
我们将单个问题编号添加到我们的集合中的方式是通过迭代/循环我们的问题编号列表(在这种情况下,我只是随机选择了三个)。对于列表中的每个问题编号,我们需要获取一个新的 CSRF 令牌,并更改标题字典中的“Referer”字段(以反映我们来自的新位置)。然后,循环中的 POST 请求是实际将当前问题添加到指定集合的请求。
而且,以防你好奇,这是我在终端中得到的输出:
(1/3) Adding issue# 41485 to collection# 27402...
(2/3) Adding issue# 41486 to collection# 27402...
(3/3) Adding issue# 41487 to collection# 27402...
All done!
推荐阅读
- python - 如何在 sympy 中用符号编写点积?
- android - 运行 Jacoco 报告时来自 @Generated 的错误
- java - 仅提供包的 Maven 测试
- c++ - 我应该用 0 还是 0.0 初始化浮点(double,float)变量?
- javascript - daysOfWeekDisabled 选项在 DateTimePicker 插件上不起作用
- c# - 多部分表单数据请求无法调用大文件大小
- python - 如何使用 FilterUserMixin 过滤 Django 中的一个或另一个字段
- javascript - 如何将 Angular .ts 文件链接到已创建的 html 页面?
- javascript - 如何使用 sinnon 从书架 js 模拟回调函数
- node.js - 使用 NPM 脚本在 CLI 参数中设置正则表达式模式时出现“(”意外错误