0

我正在使用 MechanicalSoup 通过 Python 3.6 登录网站,但我遇到了 CSRF 令牌问题。

每次我请求返回 html 时,我都会阅读“无效的 CSRF 令牌:禁止”。在登录页面上搜索 html,与标记相似的元素 id 最接近的匹配项是“autheticity_token”,它似乎已经用标记填充了。

我能够使用“re”模块来提取令牌并将其重新提交给具有我上面谈到的 id 但没有运气的元素。请注意,我必须通过 id 找到元素,因为没有为其提供名称(这就是为什么我的 Robobrowser 方法不起作用的原因)。

这是我认为对应于 CSRF 的元素:

<input id="authenticity_token" type="hidden" value="b+csp/9zR/a1yfuPPIYJSiR0v8jJUTaJaGqJmJPmLmivSn4GtLgvek0nyPvcJ0aOgeo0coHpl94MuH/r1OK5UA==">

在这种情况下,我将提取 "b+csp/9zR/a1yfuPPIYJSiR0v8jJUTaJaGqJmJPmLmivSn4GtLgvek0nyPvcJ0aOgeo0coHpl94MuH/r1OK5UA==" 并将其重新提交给该元素

这是我的代码,其中包含用户、密码和 url 的虚拟值

import mechanicalsoup
import re

def return_token(str1):
    match1 = "authenticity_token"
    match2 = ".*value\=\"(.*)\".*"
    for x in range(len(str1)):
        line = str1[x]
        if re.findall(match1,line):
            token = re.findall(match2,line)[0]
            return token

url1 = ""
username = ""
password = ""

browser = mechanicalsoup.Browser()
page = browser.get(url1)
str0 = page.text
token = return_token(str0.split('\n'))
#print(str0)
form = page.soup.find("form",{"id":"loginForm"})

form.find('input', {'name': 'username'})['value'] = username
form.find('input', {'name': 'password'})['value'] = password
form.find('input', {'id': 'authenticity_token'})['value'] = str(token)

response = browser.submit(form, page.url)
print(response.text)
4

1 回答 1

1

我认为这里的问题是<input>元素必须具有name属性才能通过 POST 或 GET 提交。由于您的令牌位于name-less<input>元素中,因此 MechanicalSoup 不会处理它,因为这是浏览器会执行的操作。

来自W3C 规范

每个成功的控件都将其控件名称与其当前值配对,作为提交的表单数据集的一部分。成功的控件必须在 FORM 元素中定义,并且必须具有控件名称。

...

控件的“控件名称”由其名称属性给出。

也许有一些 JavaScript 正在处理 CSRF 令牌。

对于类似的讨论,请参阅如果输入标签没有名称,表单数据是否仍然传输?


关于您对MechanicalSoupStatefulBrowser的使用,这些类Form将简化您的脚本。例如,如果您只需要打开页面并输入用户名和密码:

import mechanicalsoup

# These values are filled by the user
url = ""
username = ""
password = ""

# Open the page
browser = mechanicalsoup.StatefulBrowser(raise_on_404=True)
browser.open(url)

# Fill in the form values
form = browser.select_form('form[id=loginForm]')
form['username'] = username
form['password'] = password

# Submit the form and print the resulting page text
response = browser.submit_selected()
print(response.text)
于 2017-10-26T01:35:19.560 回答