如何使用Python使用POST方法刮取页面?

2024-05-23 17:59:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我想把一些报道星链星座段落的页面合并在一起。现在,我需要手动访问每个页面,不能根据时间和可见性进行筛选

基本页面是https://heavens-above.com/StarlinkLaunchPasses.aspx?lat=50&lng=12&loc=Somewhere

Scrape peekyou.com ( having POST METHOD)给了我一些提示,但还不足以让我站起来

这是抓取第一页(最后一次Starlink启动)的GET代码:

import pandas as pd
import requests
from bs4 import BeautifulSoup

res = requests.get(r"https://heavens-above.com/StarlinkLaunchPasses.aspx?lat=45.61&lng=15.312&loc=Somewhere&alt=0&tz=CET")
soup = BeautifulSoup(res.content, 'lxml')
table = str(soup.find_all("table", {"class": "standardTable"}))

df = pd.read_html(table)[0]

cols = "date satellite mag s_time s_altitude s_azimuth h_time h_altitude h_azimuth e_time e_altitude e_azimuth".split()
df.columns = cols

print(df)

单击下拉列表,通过POST方法请求其他页面。这里停止我的(肤浅的)网络刮知识

我看到返回的res.text包含我可以用于下一个请求的表单数据,但我不知道如何提取它们:

<form name="aspnetForm" method="post" action="/StarlinkLaunchPasses.aspx?lat=48.55&amp;lng=11.53&amp;loc=Somewhere&amp;alt=0&amp;tz=CET" id="aspnetForm">
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="DprSo0lEG4wbQojWQ3ub7mILDflL+omP+KQ
.../>
...
<input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="9E5B71D1" />
<input type="hidden" name="utcOffset" id="utcOffset" value="7200000" />
...
<input type="hidden" name="ctl00$cph1$hidStartUtc" id="ctl00_cph1_hidStartUtc" value="637211090517289358" />
...
# and here is the dropdown list:
<select name="ctl00$cph1$ddlLaunches" id="ctl00_cph1_ddlLaunches">
    <option selected="selected" value="2020019">Starlink 5, 18 March 2020 12:16</option>
    <option value="2020012">Starlink 4, 17 February 2020 15:06</option>
    <option value="2020006">Starlink 3, 29 January 2020 14:07</option>
    <option value="2020001">Starlink 2, 07 January 2020 02:19</option>
    <option value="2019074">Starlink 1, 11 November 2019 14:56</option>
    <option value="2019029">Starlink 0, 24 May 2019 02:30</option>
</select>

你能帮我找到一个可能的解决办法吗

先谢谢你


Tags: namecomidinputvaluetype页面hidden
2条回答

这将模拟单击下一页,将代码放在scrapy蜘蛛scrapy docs

# -*- coding: utf-8 -*-
import scrapy
from scrapy.utils.response import open_in_browser
import pandas as pd
class TestSpider(scrapy.Spider):
    name = 'test'
    allowed_domains = ['heavens-above.com']

    def start_requests(self):
        url = "https://heavens-above.com/StarlinkLaunchPasses.aspx?lat=45.61&lng=15.312&loc=Somewhere&alt=0&tz=CET"
        yield scrapy.Request(url,callback=self.parse)
    def parse(self, response):
        #open_in_browser(response) see the response
        table=response.xpath('//table[@class="standardTable"]').extract_first()
        df = pd.read_html(table)
        #do what you want the df
        #going to next page
        to_post = response.urljoin(response.xpath('//form[@name="aspnetForm"]/@action').extract_first())
        data = {
          '__EVENTTARGET': '',
          '__EVENTARGUMENT': '',
          '__LASTFOCUS': '',
          '__VIEWSTATE':response.xpath('//*[@id="__VIEWSTATE"]/@value').extract_first(),
          '__VIEWSTATEGENERATOR':response.xpath('//*[@id="__VIEWSTATEGENERATOR"]/@value').extract_first(),
          'utcOffset':response.xpath('//*[@id="utcOffset"]/@value').extract_first(),
          'ctl00$ddlCulture': 'en',
          'ctl00$cph1$hidStartUtc':response.xpath('//*[@id="ctl00_cph1_hidStartUtc"]/@value').extract_first(),
          'ctl00$cph1$ddlLaunches':response.xpath('//*[@id="ctl00$cph1$ddlLaunches"]/@value').extract_first(),
          'ctl00$cph1$ddlLaunches':response.xpath('//option[@selected="selected"]/@value').extract()[-1],
          'ctl00$cph1$btnNext': '>',
          }
        yield scrapy.http.FormRequest(to_post,callback=self.parse,formdata=data,)

对于这样一个页面,您不需要使用ScrapySelenium

您可以使用requestsbs4pandas实现您的目标

现在,让我们把计划付诸实施:


1。我们将检查您的browser{a2}下的Network Monitor,看看更改日期后会发生什么

enter image description here

  • 如您所见,我们注意到已向 host 具有多个Form data

    问:为什么你的url呼叫没有得到响应 传递POST数据

    答:因为host实际上设置了一个特定的日期,从drop downstatic,这是18 March 2020 12:16,一旦打开url就可以看到

Notes:

  1. 您不需要解析HTML并搜索表来用Pandas读取它,因为您可以在一次调用中完成!aspandas有一个名为read_html的函数,它将解析HTML并将tables作为列表为您读取。可以通过切片[]在它们之间移动
import pandas as pd

df = pd.read_html(
    "https://heavens-above.com/StarlinkLaunchPasses.aspx?lat=50&lng=12&loc=Somewhere")[0]

print(df)
  1. 您根本不需要使用raw stringPython raw string treats backslash()as a literal character,在某些情况下需要将其传递给host

2。我们将查看Form data中的所有parameters,丢弃空值"",并检查哪个valuesfilled。现在如果我们刷新页面,我们会注意到有一些values被更改了。因此,我们将检查HTML源代码,看看是否可以找到这些values

enter image description here

正如您所看到的,我们在前面的screen-shot的这一部分中找到了parametersvalues

这里是drop-down选项的important部分的值,我们需要将它传递给这个parameter{}

enter image description here

3。现在,我们需要通过维护session对象发出GET请求来解析url并收集所有必需的parameters{},然后发出post请求。而我们将用Pandas阅读它

  • 问:为什么我们不直接使用Pandas来读取HTML表? 答:因为Pandas没有传递Form data的选项,所以我们使用requests并通过data=传递Form data,然后通过read_html读取content

最后,我们将使用每个表的名称将其保存到csv文件中

最终代码

import requests
from bs4 import BeautifulSoup
import pandas as pd
import re


def Main(url):
    with requests.Session() as req:
        r = req.get(url)
        soup = BeautifulSoup(r.content, 'html.parser')
        times = [item.get("value") for item in soup.findAll(
            "option", value=re.compile(r"\d{6}"))]
        vs = soup.find("input", id="__VIEWSTATE").get("value")
        vsg = soup.find("input", id="__VIEWSTATEGENERATOR").get("value")
        ut = soup.find("input", id="ctl00_cph1_hidStartUtc").get("value")
        for time in times:
            data = {
                '__EVENTTARGET': 'ctl00$cph1$ddlLaunches',
                '__EVENTARGUMENT': '',
                '__LASTFOCUS': '',
                '__VIEWSTATE': vs,
                '__VIEWSTATEGENERATOR': vsg,
                'utcOffset': '0',
                'ctl00$ddlCulture': 'en',
                'ctl00$cph1$hidStartUtc': ut,
                'ctl00$cph1$ddlLaunches': time
            }
            r = req.post(url, data=data)
            df = pd.read_html(r.content)[0]
            df.to_csv(f"{time}.csv", index=False)


Main("https://heavens-above.com/StarlinkLaunchPasses.aspx?lat=50&lng=12&loc=Somewhere")

相关问题 更多 >