首页 > 解决方案 > 循环浏览 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 个问题。有没有一种简单的方法可以做到这一点?谢谢。

标签: pythonbrowser

解决方案


有一些空闲时间,所以我在 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!

而且,在浏览器中登录我的帐户后我的漫画收藏: 我的


推荐阅读