使用请求时无法模仿 FormRequest.from_response
Can't mimic FormRequest.from_response while using requests
我创建了两个脚本;一个使用请求模块,另一个使用 scrapy。他们都工作得一尘不染。以下是如何在该站点中手动生成结果:
- 导航到此 website
- 将此地址
2220 CLOVE TERR
放在 Property Address
旁边,然后点击搜索按钮
- 从结果页面解析
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
)
执行以下操作:
- 获取第一个(默认)
form
标签。 (_get_form)
- in found form - 获取所有相关表单字段的有效负载数据(循环内的输入标签等)
(_get_inputs)
关于您的案例 __VIEWSTATE
作为此步骤的结果包含的数据
将 formdata
参数中的字段应用于新的有效载荷。
- 获取表格 url _get_form_url
- 使用前面步骤的结果创建请求对象。
据我所知requests库没有任何类似的实现。
如果由于某种原因你不能使用 scrapy 并且如果你需要这个功能 - 可能你需要自己复制所有提到的步骤(链接到提供的 scrapy 代码的相关部分)。
我创建了两个脚本;一个使用请求模块,另一个使用 scrapy。他们都工作得一尘不染。以下是如何在该站点中手动生成结果:
- 导航到此 website
- 将此地址
2220 CLOVE TERR
放在Property Address
旁边,然后点击搜索按钮 - 从结果页面解析
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
)
执行以下操作:
- 获取第一个(默认)
form
标签。 (_get_form) - in found form - 获取所有相关表单字段的有效负载数据(循环内的输入标签等)
(_get_inputs)
关于您的案例__VIEWSTATE
作为此步骤的结果包含的数据
将formdata
参数中的字段应用于新的有效载荷。 - 获取表格 url _get_form_url
- 使用前面步骤的结果创建请求对象。
据我所知requests库没有任何类似的实现。
如果由于某种原因你不能使用 scrapy 并且如果你需要这个功能 - 可能你需要自己复制所有提到的步骤(链接到提供的 scrapy 代码的相关部分)。