使用请求时无法模仿 FormRequest.from_response

Can't mimic FormRequest.from_response while using requests

我创建了两个脚本;一个使用请求模块,另一个使用 scrapy。他们都工作得一尘不染。以下是如何在该站点中手动生成结果:

  1. 导航到此 website
  2. 将此地址 2220 CLOVE TERR 放在 Property Address 旁边,然后点击搜索按钮
  3. 从结果页面解析Block的值4759

由于 __VIEWSTATE 是与 post 请求一起发送的最重要的参数之一,以填充来自任何以 .aspx 结尾的站点的结果,我不得不在第一个脚本中使用它得到结果。

然而,当我使用 scrapy 时,我仍然可以在不显式使用 __VIEWSTATE 的情况下得到相同的结果。

使用请求:

import requests
from bs4 import BeautifulSoup

link = 'https://cityservices.baltimorecity.gov/realproperty/default.aspx'
search_address = '2220 CLOVE TERR'

with requests.Session() as s:
    s.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.104 Safari/537.36'
    key = 'ctl00$ctl00$rootMasterContent$LocalContentPlaceHolder${}'
    payload = {}
    r = s.get(link)
    soup = BeautifulSoup(r.text,"lxml")
    payload['__VIEWSTATE'] = soup.select_one("input[id='__VIEWSTATE']")['value']
    payload[key.format('txtAddress')] = search_address
    payload[key.format('btnSearch')] = 'Search'
    res = s.post(link,data=payload)
    soup = BeautifulSoup(res.text,"lxml")
    block = soup.select_one("[id$='_DataGrid1'] > tr:not(th) > td").get_text(strip=True)
    print(block)

使用scrapy:

class RealpropertySpider(Spider):
    name = 'companies'
    start_url = 'https://cityservices.baltimorecity.gov/realproperty/default.aspx'
    
    search_address = '2220 CLOVE TERR'

    def start_requests(self):
        yield Request(self.start_url)

    def parse(self, response):
        key = 'ctl00$ctl00$rootMasterContent$LocalContentPlaceHolder${}'
        formdata = {
            key.format('txtAddress'): self.search_address,
            key.format('btnSearch'): 'Search'
        }

        yield FormRequest.from_response(
            response,
            formdata=formdata,
            callback=self.parse_content
        )

    def parse_content(self, response):
        block = response.xpath("//*[contains(@id,'_DataGrid1')]/tr[not(th)]/td/text()").get()
        yield {"Block":block}

Question: Is there any way I can mimic FormRequest.from_response while using requests so that I don't need to supply __VIEWSTATE within payload to fetch the required content?

您的 scrapy 解决方案有效,因为 FormRequest.from_response() 已经加载了包含 viewstate

的表单字段
FromRequest.from_response(
            response,
            formdata=formdata,
            callback=self.parse_content
        )

执行以下操作:

  1. 获取第一个(默认)form 标签。 (_get_form)
  2. in found form - 获取所有相关表单字段的有效负载数据(循环内的输入标签等) (_get_inputs)
    关于您的案例 __VIEWSTATE 作为此步骤的结果包含的数据
    formdata 参数中的字段应用于新的有效载荷。
  3. 获取表格 url _get_form_url
  4. 使用前面步骤的结果创建请求对象。

据我所知requests库没有任何类似的实现。

如果由于某种原因你不能使用 scrapy 并且如果你需要这个功能 - 可能你需要自己复制所有提到的步骤(链接到提供的 scrapy 代码的相关部分)。