Как очистить страницу методом POST с Python? - PullRequest
0 голосов
/ 29 марта 2020

Я хочу объединить несколько страниц, которые сообщают о пассажах созвездия Starlink. Как и сейчас, мне нужно обращаться к каждой отдельной странице вручную, и я не могу отфильтровать по времени и видимости.

Базовая страница: https://heavens-above.com/StarlinkLaunchPasses.aspx?lat=50&lng=12&loc=Somewhere.

Scrap peekyou.com (с методом POST) дает мне несколько советов, но этого недостаточно, чтобы go на моих ногах.

Это GET-код для удаления первой страницы (последний запуск Starlink):

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>

Не могли бы вы помочь мне с указателем на возможное решение?

Заранее спасибо

Ответы [ 2 ]

1 голос
/ 30 марта 2020

Вам не нужно использовать Scrapy или Selenium для такой отдельной страницы.

Вы можете достичь своей цели, используя requests, bs4 и pandas.

Теперь давайте поставим план:


1 . Мы проверим Сетевой монитор в разделе browser Инструменты разработчика и посмотрим, что произойдет, как только мы изменим дату.

enter image description here

  • Как вы можете видеть, мы заметили, что POST запрос был сделан на хост с несколькими Form data.

    Q: Почему вы получили ответ на ваш звонок на URL без передачи данных POST ?

    A: Поскольку host фактически задает указанную c дату из drop down быть static, то есть 18 March 2020 12:16, как вы можете видеть после открытия URL.

Примечания:

  1. you не нужно анализировать HTML и искать таблицу, чтобы прочитать ее с помощью Pandas, как вы можете сделать это за один вызов! поскольку pandas имеет функцию 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)
вам вообще не нужно использовать необработанную строку . Python raw string treats backslash () as a literal character, который в некоторых случаях необходимо передать в host.

2 . Мы рассмотрим все parameters в пределах Form data и отбросим пустые значения "" и проверим, какое values равно filled. Теперь, если мы обновим sh страницу, мы заметим, что некоторые values изменены. Поэтому мы проверим источник HTML и посмотрим, сможем ли мы найти эти values.

enter image description here

Как вы можете видеть, мы нашли parameters с values в этой части предыдущего screen-shot.

И вот значения параметра important части drop-down, где нам нужно передать его в этот parameter ctl00$cph1$ddlLaunches.

enter image description here

3 . Теперь нам нужно будет сделать запрос GET с поддержкой объекта session, чтобы проанализировать url и собрать все наши необходимые parameters values, а затем сделать запрос post. в то время как мы будем читать это с Pandas.

  • Q: Почему мы не использовали Pandas непосредственно для чтения HTML таблицы ? A: Поскольку Pandas не имеет возможности передать Form data, поэтому мы использовали requests и передали Form data на data=, а затем прочитали content на read_html.

И, наконец, мы сохраним каждую таблицу в 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")
1 голос
/ 30 марта 2020

это будет симулировать щелчок на следующей странице, поместите код в 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,)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...