Не могу вычеркнуть имена со следующих страниц, используя запросы - PullRequest
1 голос
/ 11 февраля 2020

Я пытаюсь проанализировать имена, проходящие через несколько страниц, с помощью сценария python. С моей текущей попыткой я могу получить имена с его целевой страницы. Однако я не могу найти ни одной идеи, чтобы получить имена со следующих страниц, а также с помощью запросов и BeautifulSoup.

ссылка на сайт

Моя попытка до сих пор:

import requests
from bs4 import BeautifulSoup

url = "https://proximity.niceic.com/mainform.aspx?PostCode=YO95"

with requests.Session() as s:
    r = s.get(url)
    soup = BeautifulSoup(r.text,"lxml")
    for elem in soup.select("table#gvContractors tr:has([id*='_lblName'])"):
        name = elem.select_one("span[id*='_lblName']").get_text(strip=True)
        print(name)

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

import requests
from bs4 import BeautifulSoup

url = "https://proximity.niceic.com/mainform.aspx?PostCode=YO95"

with requests.Session() as s:
    r = s.get(url)
    soup = BeautifulSoup(r.text,"lxml")
    payload = {i['name']:i.get('value','') for i in soup.select('input[name]')}
    payload['__EVENTARGUMENT'] = 'Page$Next'
    payload.pop('btnClose')
    payload.pop('btnMapClose')
    res = s.post(url,data=payload,headers={
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36',
        'X-Requested-With':'XMLHttpRequest',
        'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
        'Referer': 'https://proximity.niceic.com/mainform.aspx?PostCode=YO95',
        })
    sauce = BeautifulSoup(res.text,"lxml")
    for elem in sauce.select("table#gvContractors tr:has([id*='_lblName'])"):
        name = elem.select_one("span[id*='_lblName']").get_text(strip=True)
        print(name)

1 Ответ

3 голосов
/ 11 февраля 2020

Переход к следующей странице осуществляется через запрос POST с курсором __VIEWSTATE.

Как вы можете сделать это с запросами:

  1. Сделать GET-запрос на первую страницу;

  2. Разобрать необходимые данные и __VIEWSTATE курсор;

  3. Подготовить запрос POST для следующей страницы с полученным курсором;

  4. Запустить его, проанализировать все данные и новый курсор для следующей страницы.

Я не буду предоставлять никакого кода, потому что для этого требуется записать почти весь код сканера.

==== Добавлено ====

Вы почти сделали это, но есть две важные вещи, которые вы пропустили.

  1. Необходимо отправить заголовки с первым запросом GET. Если заголовки не отправлены - мы получаем сломанные токены (это легко обнаружить визуально - в конце их нет ==)

  2. Нам нужно добавить __ ASYNCPOST к грузу мы отправляем. (Это очень интересно: это не булево значение True, это строка 'true')

Вот код. Я удалил bs4 и добавил l xml (мне не нравится bs4, он очень медленный). Мы точно знаем, какие данные нам нужно отправить, поэтому давайте разберем только несколько входных данных.

import re
import requests
from lxml import etree


def get_nextpage_tokens(response_body):
    """ Parse tokens from XMLHttpRequest response for making next request to next page and create payload """
    try:
        payload = dict()
        payload['ToolkitScriptManager1'] = 'UpdatePanel1|gvContractors'
        payload['__EVENTTARGET'] = 'gvContractors'
        payload['__EVENTARGUMENT'] = 'Page$Next'
        payload['__VIEWSTATEENCRYPTED'] = ''
        payload['__VIEWSTATE'] = re.search(r'__VIEWSTATE\|([^\|]+)', response_body).group(1)
        payload['__VIEWSTATEGENERATOR'] = re.search(r'__VIEWSTATEGENERATOR\|([^\|]+)', response_body).group(1)
        payload['__EVENTVALIDATION'] = re.search(r'__EVENTVALIDATION\|([^\|]+)', response_body).group(1)
        payload['__ASYNCPOST'] = 'true'
        return payload
    except:
        return None


if __name__ == '__main__':
    url = "https://proximity.niceic.com/mainform.aspx?PostCode=YO95"

    headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36',
            'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
            'Referer': 'https://proximity.niceic.com/mainform.aspx?PostCode=YO95',
            }

    with requests.Session() as s:
        page_num = 1
        r = s.get(url, headers=headers)
        parser = etree.HTMLParser()
        tree = etree.fromstring(r.text, parser)

        # Creating payload
        payload = dict()
        payload['ToolkitScriptManager1'] = 'UpdatePanel1|gvContractors'
        payload['__EVENTTARGET'] = 'gvContractors'
        payload['__EVENTARGUMENT'] = 'Page$Next'
        payload['__VIEWSTATE'] = tree.xpath("//input[@name='__VIEWSTATE']/@value")[0]
        payload['__VIEWSTATEENCRYPTED'] = ''
        payload['__VIEWSTATEGENERATOR'] = tree.xpath("//input[@name='__VIEWSTATEGENERATOR']/@value")[0]
        payload['__EVENTVALIDATION'] = tree.xpath("//input[@name='__EVENTVALIDATION']/@value")[0]
        payload['__ASYNCPOST'] = 'true'
        headers['X-Requested-With'] = 'XMLHttpRequest'

        while True:
            page_num += 1
            res = s.post(url, data=payload, headers=headers)

            print(f'page {page_num} data: {res.text}')  # FIXME: Parse data

            payload = get_nextpage_tokens(res.text)  # Creating payload for next page
            if not payload:
                # Break if we got no tokens - maybe it was last page (it must be checked)
                break

Важно

Ответ не является правильно сформированным HTML. Таким образом, вы должны иметь дело с этим: разрезать стол или что-то еще. Удачи!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...