我正在使用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==">
我会提取,在这种情况下&#34; b + csp / 9zR / a1yfuPPIYJSiR0v8jJUTaJaGqJmJPmLmivSn4GtLgvek0nyPvcJ0aOgeo0coHpl94MuH / r1OK5UA ==&#34;并将其重新提交给该元素
这是我的代码,其中包含user,pass和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)
答案 0 :(得分:1)
我认为这里的问题是<input>
元素必须具有name
属性才能通过POST或GET提交。由于您的令牌位于name
- 少<input>
个元素中,因此它不会被MechanicalSoup处理,因为这是浏览器的功能。
每个成功的控件都将其控件名称与其当前值配对,作为提交的表单数据集的一部分。必须在FORM元素中定义成功的控件,并且必须具有控件名称。
...
控件的名称&#34;控制名称&#34;由name属性给出。
也许有一些JavaScript正在处理CSRF令牌。
有关类似的讨论,请参阅Does form data still transfer if the input tag has no name?
关于您对MechanicalSoup的使用,类StatefulBrowser
和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)