Как можно вставить информацию в input поля и спарсить страницу без Selenium?

Суть в том, как спарсить страницу, если нужная информация появляется после ввода нужных полей (улицы и дома). Я сделал это лишь с помощью Selenium и ChromeDriver'ом, но можно ли это сделать без открытия браузера просто скриптом?

Мой код:

def puff_info(street_id, house_id):
    options = webdriver.ChromeOptions()
    options.add_experimental_option('excludeSwitches', ['enable-logging'])
    browser = webdriver.Chrome(options=options, executable_path="C:/chromedriver.exe")
    browser.get("https://open.e-nkama.ru/shutdowns")
    time.sleep(6)
    street = browser.find_element_by_name("street").send_keys(street_id)
    time.sleep(2)
    itemstreet = browser.find_element_by_class_name("MuiAutocomplete-option").click()
    house = browser.find_element_by_name("house").send_keys(house_id)
    time.sleep(2)
    itemhouse = browser.find_element_by_class_name("MuiAutocomplete-option").click()
    time.sleep(5)
    table = browser.find_element_by_class_name("MuiTableBody-root")
    row = table.find_element_by_tag_name("tr")
    col = row.find_elements_by_tag_name("td")

    typen, status, date_begin, date_end = col[0].text, col[1].text, col[2].text, col[3].text
    return typen, date_begin, date_end, status

Сам сайт: https://open.e-nkama.ru/shutdowns


Ответы (1 шт):

Автор решения: gil9red

Посмотрел какие запросы сайт отправляет и накидал их:

  • Все запросы идут на сайт https://nizhnekamsk.apigate.opencity.pro/api/jsonrpc
  • В запросе нужно передавать заголовок Authorization с значением Bearer, скорее всего сайт будет менять это значение время от времени
  • Все запросы являются POST с телом JSON, ключи:
    • jsonrpc - равно 2.0
    • method - логика запроса, например opencity.gis.street.index вернет улицы по названию
    • id - какой-то UUID, похоже на рандомный, т.к. для одного и того же запроса разные значения подставляет сайт
    • params - передает фильтр и сортировку
    • Пример JSON для поиска улиц:
      {"jsonrpc":"2.0","method":"opencity.gis.street.index","id":"b1865e77-3f86-452d-b2ad-87849541bebe","params":{"limit":20,"offset":0,"filter":{"name":{"$like":"%Ленина (Кармалы)%"}}}}
      

Реализация:

import uuid
from typing import List

import requests


URL_JSONRPC = 'https://nizhnekamsk.apigate.opencity.pro/api/jsonrpc'

session = requests.Session()
session.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:94.0) Gecko/20100101 Firefox/94.0'
session.headers['Authorization'] = 'Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJydS5nb3MtZGV2LmF1dGgiLCJpYXQiOjE2MDIxNzAwNzIsImV4cCI6MTAwMDE2MDIxNzAwNzEsInN1YiI6ImYxODIyMTMwLTI2OTctNDk5Ni1hNDExLWI4NzQwMzZlYjYxMyJ9.HmQJ5vL6fSzejEbEMzihDLDiwv86545JGuB3_MRlYe8'


def send_data(method: str, params: dict) -> dict:
    data = {
        "jsonrpc": "2.0",
        "method": method,
        "id": str(uuid.uuid4()),
        "params": params,
    }
    rs = session.post(URL_JSONRPC, json=data)
    rs.raise_for_status()

    return rs.json()


def get_first_street_id(street_name: str) -> int:
    rs = send_data(
        "opencity.gis.street.index",
        {
            "limit": 20, "offset": 0,
            "filter": {"name": {"$like": f"%{street_name}%"}}
        }
    )
    return rs['result']['items'][0]['id']


def get_first_house_id(street_id: int, house_number: str) -> int:
    rs = send_data(
        "opencity.gis.house.index",
        {
            "filter": {"streetId": {"$eq": street_id}, "houseNumber": {"$like": f"{house_number}%"}},
            "limit": 0, "offset": 0,
            "sort": [{"field": "houseNumber", "desc": "ASC"}]
        }
    )
    return rs['result']['items'][0]['id']


def get_interrupts(house_id: int) -> List[dict]:
    rs = send_data(
        "opencity.interrupt.index",
        {
            "filter": {
                "houseId": {
                    "$eq": house_id
                }
            },
            "limit": 20, "offset": 0,
            "sort": [{"field": "dateStart", "desc": "DESC"}]
        }
    )
    return rs['result']['items']

Использование:

street_id = get_first_street_id('Ленина (Кармалы)')
print(f'street_id: {street_id}')
# street_id: 297

house_id = get_first_house_id(street_id, '1')
print(f'house_id: {house_id}')
# house_id: 1978

print()

for item in get_interrupts(house_id):
    print(item['body'])

Результат:

street_id: 297
house_id: 1978

Эл/во (полностью). ВК-10кВ Ф-6 ПС Б.Толкиш отпайка на ктп 118 ,выборочная замена изоляторов,опора №58 установка траверсы на подвесных изоляторах. С 8-00 до 17-00  03/11/21  №9
Эл/во (полностью). ВК-10кВ Ф-6 ПС Б.Толкиш отпайка на ктп 118 опора №9 выправка,установка траверсы на подвесных изоляторах,опоры №27,28 выправка. С 8-00 до 17-00  02/11/21  №9

P.S.

Чтобы у https://nizhnekamsk.apigate.opencity.pro/ было меньше возможных подозрений о легальности запросов, можно заполнять больше заголовков, типа:

Origin: https://open.e-nkama.ru
Referer: https://open.e-nkama.ru/
→ Ссылка