【问题标题】:Difficulty scraping data with python requests from an asp.net form on a webpage (.aspx)使用 python 请求从网页 (.aspx) 上的 asp.net 表单中难以抓取数据
【发布时间】:2020-11-11 12:06:08
【问题描述】:

我正在尝试从填写表单后返回的多页表中抓取数据。 有问题的原始表单的 URL 是https://ndber.seai.ie/Pass/assessors/search.aspx

https://kaijento.github.io/2017/05/04/web-scraping-requests-eventtarget-viewstate/ 我得到代码,该代码从空白表单中提取隐藏变量,然后与 POST 请求一起发送以获取数据

import requests
from bs4 import BeautifulSoup

url='https://ndber.seai.ie/PASS/Assessors/Search.aspx'

with requests.session() as s:
    s.headers['user-agent'] = 'Mozilla/5.0'
    r    = s.get(url)
    soup = BeautifulSoup(r.content, 'html5lib')
    target = 'ctl00$DefaultContent$AssessorSearch$gridAssessors$grid_pager'

    # unsupported CSS Selector 'input[name^=ctl00][value]'
    data = { tag['name']: tag['value'] 
        for tag in soup.select('input[name^=ctl00]') if tag.get('value')
    }
    state = { tag['name']: tag['value'] 
        for tag in soup.select('input[name^=__]')
    }
    data.update(state)
    data['__EVENTTARGET'] = ''
    data['__EVENTARGUMENT'] = ''
    print(data)
    r = s.post(url, data=data)
    new_soup = BeautifulSoup(r.content, 'html5lib')
    print(new_soup)

最初的.get很好,我得到了空白表单的html,我可以将参数提取到数据中。

但是,.post 返回一个 html 页面,表明发生了错误,但没有有用的数据。

请注意,结果被拆分为多个页面,当您从一个页面转到另一个页面时,会为以下参数指定值

data['__EVENTTARGET'] = 'ctl00$DefaultContent$AssessorSearch$gridAssessors$grid_pager' 
data['__EVENTARGUMENT'] = '1$n' # where n is the number of the age to retrieve

在上面的代码中,我最初只是尝试获取结果的第一页,然后一旦工作正常,我将制定循环以遍历所有结果并加入它们。

有没有人知道如何处理这种情况?

谢谢/科尔姆

【问题讨论】:

  • 继续挖掘后,我找到了 stackoverflow.com/questions/12645849/…,然后我用 python 搜索特定于 aspx 的网络抓取,然后我找到了 kaijento.github.io/2017/05/04/…,我现在正在拖网/爬行。跨度>
  • 上面的评论不再相关,它来自我现在更新的原始帖子。
  • 您需要在数据参数中使用ctl00_DefaultContent_AssessorSearch_captcha 的值,以便通过发布请求发送相同的内容以获取所需的内容。事实证明,上述键的值是动态的,我非常怀疑您是否可以在页面源代码中找到它。
  • 当!它看起来好像在做 AJAX'y 的事情来获得在每次重新加载页面时都会改变的值。这几乎让我想每天对 27 页的结果进行复制/粘贴,只是为了对他们不屑一顾。 #souchforopendata 感谢@SIM 提供的指针
  • 我花了大约 10 分钟来复制粘贴,不知道我是否可以每天都这样做!重复性压力损伤的风险。

标签: python asp.net web-scraping python-requests


【解决方案1】:

您可以使用请求模块从该网站获取遍历多个页面的表格内容。在这种情况下,您必须发送多个带有适当参数的发布请求才能访问内容。

与其他参数不同,有一个键ctl00$DefaultContent$AssessorSearch$captcha,其值是动态生成的,并且不存在于页面源中。

但是,您仍然可以使用此 requests_html 库获取该键的值。仅供参考,requestsrequests_html 库属于同一作者。您只需使用此函数get_captcha_value() 一次即可获取验证码的值,然后您可以重复使用相同的值直到结束。

下面的脚本当前从所有页面中获取所有名称。您可以修改选择器以获取您感兴趣的其他字段。

你可以这样做:

import requests
from bs4 import BeautifulSoup
from requests_html import HTMLSession

link = 'https://ndber.seai.ie/Pass/assessors/search.aspx'

payload = {
    'ctl00$DefaultContent$AssessorSearch$dfSearch$Name': '',
    'ctl00$DefaultContent$AssessorSearch$dfSearch$CompanyName': '',
    'ctl00$DefaultContent$AssessorSearch$dfSearch$County': '',
    'ctl00$DefaultContent$AssessorSearch$dfSearch$searchType': 'rbnDomestic',
    'ctl00$DefaultContent$AssessorSearch$dfSearch$Bottomsearch': 'Search'
}

page = 1

def get_captcha_value():
    with HTMLSession() as session:
        r = session.get(link)
        r.html.render(sleep=5)
        captcha_value = r.html.find("input[name$='$AssessorSearch$captcha']",first=True).attrs['value']
        return captcha_value

with requests.Session() as s:
    s.headers['User-Agent'] = 'Mozilla/5.0 (WindowMozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.90 Safari/537.36'
    r = s.get(link)
    soup = BeautifulSoup(r.text,"lxml")
    payload['__VIEWSTATE'] = soup.select_one("#__VIEWSTATE")['value']
    payload['__VIEWSTATEGENERATOR'] = soup.select_one("#__VIEWSTATEGENERATOR")['value']
    payload['__EVENTVALIDATION'] = soup.select_one("#__EVENTVALIDATION")['value']
    payload['ctl00$forgeryToken'] = soup.select_one("#ctl00_forgeryToken")['value']
    payload['ctl00$DefaultContent$AssessorSearch$captcha'] = get_captcha_value()
    
    while True:
        res = s.post(link,data=payload)
        soup = BeautifulSoup(res.text,"lxml")
        if not soup.select_one("table[id$='gridAssessors_gridview'] tr[class$='RowStyle']"): break
        for items in soup.select("table[id$='gridAssessors_gridview'] tr[class$='RowStyle']"):
            _name = items.select_one("td > span").get_text(strip=True)
            print(_name)

        page+=1
        payload = {i['name']:i.get('value','') for i in soup.select('input[name]')}
        payload.pop('ctl00$DefaultContent$AssessorSearch$dfSearchAgain$Feedback')
        payload.pop('ctl00$DefaultContent$AssessorSearch$dfSearchAgain$Search')
        payload['__EVENTTARGET'] = 'ctl00$DefaultContent$AssessorSearch$gridAssessors$grid_pager'
        payload['__EVENTARGUMENT'] = f'1${page}'

【讨论】:

  • 哦,这看起来不错。给我一个尝试的机会。谢谢@SIM
  • 它给出了一条错误消息“RuntimeError:无法在现有事件循环中使用 HTMLSession。请改用 AsyncHTMLSession。”源自“r.html.render(sleep=5)”行。我试试看。
  • 顺便说一句,我在 kaggle.com 中运行代码,我想知道这个上下文是否有所作为?
  • 我不知道你为什么在执行脚本时遇到了这个错误。我想给你一个video demo 作为概念证明它在我的最终表现如何。
  • 好的,我会在我的本地机器上测试它,但是从视频上看确实不错。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-08
  • 2022-01-18
相关资源
最近更新 更多