Невозможно очистить имя с веб-страницы с помощью запросов - PullRequest
1 голос
/ 01 апреля 2019

Я создал скрипт на python для извлечения имени, которое заполняется при заполнении ввода на веб-странице. Вот как вы можете получить это имя -> после открытия этой веб-страницы (ссылка на сайт приведена ниже), поместите 16803 рядом с CP Number и нажмите кнопку поиска.

Я знаю, как получить это, используя selenium, но мне не интересно идти по этому пути. Я пытаюсь собрать имя с помощью модуля requests. Я попытался имитировать шаги (что я вижу в инструментах chrome dev) в моем скрипте относительно того, как запросы отправляются на этот сайт. Единственное, что я не могу поставить автоматически в параметре payload, это ScrollTop.

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

Это моя попытка:

import requests
from bs4 import BeautifulSoup

URL = "https://www.icsi.in/student/Members/MemberSearch.aspx"

with requests.Session() as s:
    r = s.get(URL)
    cookie_item = "; ".join([str(x)+"="+str(y) for x,y in r.cookies.items()])
    soup = BeautifulSoup(r.text,"lxml")

    payload = {
        'StylesheetManager_TSSM':soup.select_one("#StylesheetManager_TSSM")['value'],
        'ScriptManager_TSM':soup.select_one("#ScriptManager_TSM")['value'],
        '__VIEWSTATE':soup.select_one("#__VIEWSTATE")['value'],
        '__VIEWSTATEGENERATOR':soup.select_one("#__VIEWSTATEGENERATOR")['value'],
        '__EVENTVALIDATION':soup.select_one("#__EVENTVALIDATION")['value'],
        'dnn$ctlHeader$dnnSearch$Search':soup.select_one("#dnn_ctlHeader_dnnSearch_SiteRadioButton")['value'],
        'dnn$ctr410$MemberSearch$ddlMemberType':0,
        'dnn$ctr410$MemberSearch$txtCpNumber': 16803,
        'ScrollTop': 474,
        '__dnnVariable': soup.select_one("#__dnnVariable")['value'],
    }

    headers = {
        'Content-Type':'multipart/form-data; boundary=----WebKitFormBoundaryBhsR9ScAvNQ1o5ks',
        'Referer': 'https://www.icsi.in/student/Members/MemberSearch.aspx',
        'Cookie':cookie_item,
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
    }
    res = s.post(URL,data=payload,headers=headers)
    soup_obj = BeautifulSoup(res.text,"lxml")
    name = soup_obj.select_one(".name_head > span").text
    print(name)

Когда я выполняю вышеуказанный скрипт, я получаю следующую ошибку:

AttributeError: 'NoneType' object has no attribute 'text'

Как получить имя, которое вводится при заполнении ввода на веб-странице с использованием запросов?

1 Ответ

2 голосов
/ 05 апреля 2019

Основная проблема с вашим кодом - это кодировка данных. Я заметил, что вы установили заголовок Content-Type на «multipart / form-data», но этого недостаточно для создания многочастных закодированных данных. Фактически это проблема, потому что фактическая кодировка отличается, так как вы используете параметр data, который URL-кодирует данные POST. Для создания данных, состоящих из нескольких частей, вы должны использовать параметр files.

Вы можете сделать это либо передав дополнительный фиктивный параметр в files,

res = s.post(URL, data=payload, files={'file':''})

(это изменило бы кодировку для всех данных POST, а не только для поля 'file')

Или вы можете преобразовать значения в вашем словаре payload в кортежи, что является ожидаемой структурой при публикации файлов с запросами.

payload = {k:(None, str(v)) for k,v in payload.items()}

Первое значение для имени файла; в этом случае он не нужен, поэтому я установил None.

Затем ваши данные POST должны содержать значение __EVENTTARGET, необходимое для получения правильного ответа. (При создании словаря данных POST важно предоставить все данные, которые ожидает сервер. Мы можем получить эти данные из браузера: либо путем проверки формы HTML, либо путем проверки сетевого трафика.) Полный код,

import requests
from bs4 import BeautifulSoup

URL = "https://www.icsi.in/student/Members/MemberSearch.aspx"

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['dnn$ctr410$MemberSearch$txtCpNumber'] = 16803
    payload["__EVENTTARGET"] = 'dnn$ctr410$MemberSearch$btnSearch'
    payload = {k:(None, str(v)) for k,v in payload.items()}

    r = s.post(URL, files=payload)
    soup_obj = BeautifulSoup(r.text,"lxml")
    name = soup_obj.select_one(".name_head > span").text
    print(name)

После еще нескольких тестов я обнаружил, что сервер также принимает данные в кодировке URL (вероятно, из-за отсутствия опубликованных файлов). Таким образом, вы можете получить действительный ответ либо с data, либо с files, при условии, что вы не измените заголовок Content-Type по умолчанию.

Нет необходимости добавлять дополнительные заголовки. При использовании объекта Session файлы cookie сохраняются и отправляются по умолчанию. Заголовок Content-Type создается автоматически - «application / x-www-form-urlencoded» при использовании параметра data, «multipart / form-data» с использованием files. Изменение агента пользователя по умолчанию или добавление Referer не требуется.

...