Python Web-Scraping CSRF令牌问题

时间:2017-10-25 22:05:13

标签: python web-scraping beautifulsoup urllib mechanicalsoup

我正在使用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)

1 个答案:

答案 0 :(得分:1)

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

来自W3C specification

  

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

     

...

     

控件的名称&#34;控制名称&#34;由name属性给出。

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

有关类似的讨论,请参阅Does form data still transfer if the input tag has no name?

关于您对MechanicalSoup的使用,类StatefulBrowserForm会简化您的脚本。例如,如果您只需打开页面并输入用户名和密码:

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)