Невозможно разобрать имена с третьей страницы и далее

Я создал сценарий на Python, используя модуль запросов и библиотеку BeautifulSoup, чтобы получить имена разных участников с веб-сайта. Скрипт может безупречно получить имя с первой и второй страниц. Тем не менее, он удаляет те же имена с третьей страницы и далее. Я мог заметить, что логика следующей страницы находится в пределах значения __EVENTTARGET, как в dnn$ctr410$MemberSearch$grdMembers$ctl00$ctl02$ctl01$ctl07, dnn$ctr410$MemberSearch$grdMembers$ctl00$ctl02$ctl01$ctl09 и так далее. Сценарий может соответственно увеличивать числа, но результат после второй страницы остается прежним.

Чтобы заполнить результаты этого website, все, что вам нужно сделать, это нажать кнопку поиска, ничего не меняя. Затем вы можете щелкнуть по страницам 2,3,4 e.t.c, чтобы перейти на соответствующую страницу.

Я пробовал (соскабливая данные с первых двух страниц):

import requests
from bs4 import BeautifulSoup

link = 'https://www.icsi.in/student/Members/MemberSearch.aspx?SkinSrc=%5BG%5DSkins/IcsiTheme/IcsiIn-Bare&ContainerSrc=%5BG%5DContainers/IcsiTheme/NoContainer'

with requests.Session() as s:
    s.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.1; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'
    r = s.get(link)
    soup = BeautifulSoup(r.text,"lxml") 
    payload = {i['name']:i.get('value','') for i in soup.select('input[name]')}
    payload['__EVENTTARGET'] = 'dnn$ctr410$MemberSearch$btnSearch'

    page = 5
    while True:
        r = s.post(link,data=payload)
        soup = BeautifulSoup(r.text,"lxml")
        for item in soup.select("span[id$='_lblFullName']"):
            print(item.text)

        page+=2
        payload = {i['name']:i.get('value','') for i in soup.select('input[name]')}
        if len(str(page))==1:
            payload['__EVENTTARGET'] = 'dnn$ctr410$MemberSearch$grdMembers$ctl00$ctl02$ctl01$ctl0{}'.format(page)
        else:
            payload['__EVENTTARGET'] = 'dnn$ctr410$MemberSearch$grdMembers$ctl00$ctl02$ctl01$ctl{}'.format(page)

        payload['__dnnVariable'] = {'__scdoff':'1','__dnn_pageload':'__dnn_setScrollTop();'}
        payload['ScrollTop'] = '400'

Как мне получить имена с остальных страниц после второй страницы?


person MITHU    schedule 11.05.2020    source источник
comment
Это похоже на страницу ASP.NET - она ​​может отправлять много значений POST - не только __EVENTTARGET - и вам, возможно, придется отправить их все - также как POST запрос. ПЕРВЫЙ: используйте DevTools в Firefox / Chrome, чтобы увидеть все запросы, отправленные из браузера, когда вы переходите на следующую страницу, и посмотрите, какие значения он отправляет, и если это GET или POST запрос. Ваш код должен отправить то же самое.   -  person furas    schedule 11.05.2020
comment
Я отправляю, наверное, все. Если вы распечатаете полезную нагрузку, вы увидите, что там присутствуют необходимые параметры. Спасибо.   -  person MITHU    schedule 11.05.2020
comment
Кстати, вы можете использовать "{:02}".format(7), чтобы получить 07 вместо 7, и тогда вам не нужно проверять if len(str(page))==1: (Кстати: вместо if len(str(page))==1: вы можете просто проверить if page < 10:)   -  person furas    schedule 11.05.2020
comment
когда я проверяю payload.keys() и сравниваю с ключами, отправленными в веб-браузере, я вижу ключи, которые браузер не отправляет, т.е. клавиши для кнопок со стрелками (для перехода к первой / последней / предыдущей / следующей странице) и, возможно, это создает проблему. т.е. dnn$ctr410$MemberSearch$grdMembers$ctl00$ctl02$ctl01$ctl02 для кнопки перехода на первую страницу.   -  person furas    schedule 11.05.2020
comment
Я добавил эту строку payload.pop('dnn$ctr410$MemberSearch$grdMembers$ctl00$ctl02$ctl01$ctl02') в конец цикла while, чтобы исключить ключ из полезной нагрузки, но это, похоже, не решает проблемы. Спасибо.   -  person MITHU    schedule 11.05.2020
comment
но может быть много других имен, потому что есть другие кнопки, т.е. Я видел ...ctl28 для стрелки, ведущей к следующей странице (но я не уверен, не использует ли она другое имя, если отображается меньше страниц). Я не уверен, но страницы также могут использовать JavaScript для вычисления __EVENTVALIDATION, и сервер может это проверить, но _3 _ / _ 4_ не может запускать JavaScript.   -  person furas    schedule 11.05.2020
comment
@MITHU проверьте ответ ниже   -  person αԋɱҽԃ αмєяιcαη    schedule 11.05.2020


Ответы (2)


Он начинает работать, если я удаляю из элементов полезной нагрузки такие ключи, как dnn$ctr410$MemberSearch$grdMembers$ctl00$ctl02$ctl01$ctl02, которые являются клавишами для кнопок со стрелками.

    name_length = len('dnn$ctr410$MemberSearch$grdMembers$ctl00$ctl02$ctl01$ctl02')

    for key in list(payload.keys()):
        if key.startswith('dnn') and len(key) == name_length:
            payload.pop(key)
            print(key)

но вы можете использовать метод из αԋɱҽԃ αмєяιcαη ответа, чтобы убедиться, что вы отправляете только необходимые значения.


import requests
from bs4 import BeautifulSoup

link = 'https://www.icsi.in/student/Members/MemberSearch.aspx?SkinSrc=%5BG%5DSkins/IcsiTheme/IcsiIn-Bare&ContainerSrc=%5BG%5DContainers/IcsiTheme/NoContainer'

with requests.Session() as s:
    s.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.1; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'
    r = s.get(link)
    soup = BeautifulSoup(r.text,"lxml")

    payload = {i['name']:i.get('value','') for i in soup.select('input[name]')}
    payload['__EVENTTARGET'] = 'dnn$ctr410$MemberSearch$btnSearch'

    page = 5
    while True:

        r = s.post(link, data=payload)
        soup = BeautifulSoup(r.text, "lxml")
        for item in soup.select("span[id$='_lblFullName']"):
            print(item.text)

        page += 2

        payload = {i['name']:i.get('value','') for i in soup.select('input[name]')}
        payload['__EVENTTARGET'] = 'dnn$ctr410$MemberSearch$grdMembers$ctl00$ctl02$ctl01$ctl{:02}'.format(page)

        name_length = len('dnn$ctr410$MemberSearch$grdMembers$ctl00$ctl02$ctl01$ctl02')
        for key in list(payload.keys()):
            if key.startswith('dnn') and len(key) == name_length:
                payload.pop(key)
                print(key)

        payload['__dnnVariable'] = {'__scdoff':'1','__dnn_pageload':'__dnn_setScrollTop();'}
        payload['ScrollTop'] = '400'

РЕДАКТИРОВАТЬ: на странице используется более сложная система, и после 10 страниц отображаются новые ссылки, но со старыми значениями ctl07, ctl09. Вместо этих ссылок я использую имя из кнопки со стрелкой на следующую страницу - в начале оно имеет значение ctrl28, но после 10 страниц оно имеет ctrl30 (поскольку ссылок больше - он добавляет ссылки ... на следующий / предыдущий список из 10 страниц)

import requests
from bs4 import BeautifulSoup

link = 'https://www.icsi.in/student/Members/MemberSearch.aspx?SkinSrc=%5BG%5DSkins/IcsiTheme/IcsiIn-Bare&ContainerSrc=%5BG%5DContainers/IcsiTheme/NoContainer'

with requests.Session() as s:
    s.headers['User-Agent'] = 'Mozilla/5.0 (Windows NT 6.1; ) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Safari/537.36'
    r = s.get(link)
    soup = BeautifulSoup(r.text,"lxml")

    payload = {i['name']:i.get('value','') for i in soup.select('input[name]')}
    payload['__EVENTTARGET'] = 'dnn$ctr410$MemberSearch$btnSearch'

    page = 1  # I don't need it to generate lins, now I use it only to display page number
    while True:
        print('page:', page)
        page += 1

        r = s.post(link, data=payload)
        soup = BeautifulSoup(r.text, "lxml")
        for item in soup.select("span[id$='_lblFullName']"):
            print(item.text)

        payload = {i['name']:i.get('value','') for i in soup.select('input[name]')}

        name_length = len('dnn$ctr410$MemberSearch$grdMembers$ctl00$ctl02$ctl01$ctl28')
        for key in list(payload.keys()):
            if key.startswith('dnn') and len(key) == name_length:
                payload.pop(key)
                #print(key)

        # button with arrow to next page

        next_page = soup.select("input[class='rgPageNext']")
        if not next_page:
            break

        next_page = next_page[0]['name']
        print(next_page)
        payload[next_page] = ''

        payload['__dnnVariable'] = {'__scdoff':'1','__dnn_pageload':'__dnn_setScrollTop();'}
        payload['ScrollTop'] = '400'
person furas    schedule 11.05.2020
comment
После 12 или 13 страниц скрипт начинает многократно выдавать результаты предыдущей страницы. - person MITHU; 11.05.2020
comment
вы проверяли это в веб-браузере? Вероятно, он использует другие значения, чем вы ожидаете. Теперь я проверил ссылку на страницу 11, и она снова использует ctl07 вместо ctl25 - так что она работает иначе, чем мы могли ожидать. - person furas; 11.05.2020
comment
вместо генерации значения для '__EVENTTARGET' я использовал имя из select("input[class='rgPageNext']")[0]['name'] (кнопка со стрелкой на следующую страницу), а затем получаю правильные значения даже после 10 страниц. - person furas; 11.05.2020

На самом деле вам нужно было включить полные Payload параметры поста.

Мы должны сделать это в рамках того же Session с использованием requests.Session(), поскольку при разбивке на страницы веб-сайта используется поворот function на основе __dnnVariable, который сервер получает по запросу JS, который транслируется в цикл.

Где это на самом деле означает Next

Итак, я сначала сделал GET запрос и получил необходимые params (некоторые из них динамические, а другие статические)

Затем я сделал запрос на публикацию под тем же session

import requests
import re
from bs4 import BeautifulSoup
from urllib.parse import unquote

data = {
    '__EVENTTARGET': "dnn$ctr410$MemberSearch$btnSearch",
    '__EVENTARGUMENT': '',
    '__VIEWSTATEENCRYPTED': '',
    'dnn$ctlHeader$dnnSearch$Search': 'SiteRadioButton',
    'dnn$ctlHeader$dnnSearch$txtSearch': '',
    'dnn$ctr410$MemberSearch$txtFirstName': '',
    'dnn$ctr410$MemberSearch$txtLastName': '',
    'dnn$ctr410$MemberSearch$ddlMemberType': 0,
    'dnn$ctr410$MemberSearch$txtMembershipNumber': '',
    'dnn$ctr410$MemberSearch$txtCpNumber': '',
    'dnn$ctr410$MemberSearch$txtCity': '',
    'dnn$ctr410$MemberSearch$txtOrganisation': '',
    'dnn$ctr410$MemberSearch$txtAddress2': '',
    'dnn$ctr410$MemberSearch$txtAddress3': '',
    'dnn$ctr410$MemberSearch$txtEmail': '',
    'dnn_ctr410_MemberSearch_grdMembers_ClientState': '',
    'ScrollTop': 432,
    '__dnnVariable': '{"__scdoff":"1","__dnn_pageload":"__dnn_setScrollTop();"}'
}


def main(url):
    with requests.Session() as req:
        r = req.get(url)
        soup = BeautifulSoup(r.content, 'html.parser')
        data['StylesheetManager_TSSM'] = re.search(
            r"hf.value \+= '(.*?)\'", r.text).group(1)
        data['ScriptManager_TSM'] = unquote(soup.findAll('script', src=True)
                                            [2]['src']).split("=", 3)[-1]
        data['__VIEWSTATE'] = soup.find("input", id="__VIEWSTATE").get("value")
        data['__VIEWSTATEGENERATOR'] = soup.find(
            "input", id="__VIEWSTATEGENERATOR").get("value")
        data['__EVENTVALIDATION'] = soup.find(
            "input", id="__EVENTVALIDATION").get("value")

        for _ in range(10):
            r = req.post(url, data=data)
            soup = BeautifulSoup(r.content, 'html.parser')
            names = [name.text for name in soup.select("div.name_head")]
            page = soup.select_one(
                "a.rgCurrentPage").next_sibling['href'].split("'")[1]
            data['__EVENTTARGET'] = page
            data['__EVENTVALIDATION'] = soup.find(
                "input", id="__EVENTVALIDATION").get("value")
            data['__VIEWSTATE'] = soup.find(
                "input", id="__VIEWSTATE").get("value")
            print(names)


main("https://www.icsi.in/student/Members/MemberSearch.aspx")

Примечание: по каждому запросу вы будете получать данные не в порядке сортировки, поскольку функция search использует random на внутреннем сервере.

Выход:

['SH. DILIP RAGHUNATH KOTWAL', 'SH. ARUNODAY ROY MUKHERJEE', 'SH. J SUBRAMANI', 'SH. R KRISHNAMANI', 'SH. R NARAYANASWAMI', 'SH. M V GOPALAKRISHNAN', 'SH. RAJAM KRISHNAMURTHY', 'SH. V SIVASUBRAMANIAN', 'SH. V RAGHAVENDRAN', 'SH. G V AIMAN']
['SH. K J MATHEW', 'SH. K K GHOSH', 'SH. SUBHASH CHANDER DHAWAN', 'SH. BABU RAM MAHESWARI', 'SH. S SWAMINATHAN', 'SH. T S A AIYER', 'SH. KOVILOOR VIJAYARAGHAVACHARI SAMPATHKUMAR', 'SH. M KRISHNAN', 'SH. R N BANSAL', 'SH. N V RAMAN']
['SH. R VENKATARAMANI', 'SH. UTPALENDU ROY CHOUDHURY', 'SH. LAKSHMI NARAYANAN V', 'SH. PARIJAT KUMAR HORE', 'SH. B R VENKATESAN', 'SH. KISHAN GOPAL SOMANI', 'SH. O P GANERIWALA', 'SH. P T KUPPUSWAMY', 'SH. U P MATHUR', 'SH. N N UPADHYAY']
['SH. N K BHANDARI', 'SH. S R C SETTY', 'SH. S V BALASUBRAMANIAN', 'SH. HOSHIE HIRJI MALGHAM', 'SH. KAIKOBAD SORABJI ITALIA', 'SH. K SIVADAS', 'SH. K K SIVARAMAKRISHNAN', 'SH. A CHANDRASEKARAN', 'SH. R PONNAMBALAM', 'SH. T K B VENKATARAMAN']
['SH. NARINDER PAL', 'SH. PARKASH ATAM', 'SH. K A PARTHASARATHY', 'SH. SURESH CHANDRA OSWAL', 'SH. MAHENDRA KANTILAL SHAH', 'SH. V. SANTHANAKRISHNA', 'SH. VASANT NARAYAN GOGATE', 'SH. MANEKLAL 
PATEL', 'SH. B N VISHWANATH', 'SH. B S L NARAYAN']
['SH. P L N VIJAYANAGAR', 'SH. SHREEPAD MARTAND  KORDE', 'SH. SHIV BHAGWAN KOTHARI', 'SH. R B POPLAI', 'SH. RAMESH KHANNA', 'SH. RAVINDER NATH JOSHI', 'SH. VIDYA SAGAR AGGARWAL', 'SH. ARVIND JAYKUMAR CHAKOTE', 'SH. V RAMASESHAN', 'SH. BADRINARAYAN BALDAWA']
['SH. C GOVINDANKUTTY', 'SH. A G MADHAVAN', 'SH. DHIRAJ NATH BHATTACHARYYA', 'SH. RAMESHWAR LAL INANI', 'SH. RAMESHWARDAS C DAGA', 'SH. R SUBRAMANIAN', 'SH. S M REGE', 'SH. NARENDRA KUMAR KAPOOR', 'SH. K RAMAMURTHI', 'SH. ROOPENDRA NARAYAN ROY']
['SH. KALYAN KUMAR MITRA', 'SH. KALYANASUNDARAM ', 'SH. N A SESHADRI', 'SH. RAJENDRA KUMAR JAIN', 'SH. BISWAJIT SEN', 'SH. RAMKRISHNA NATHOOMAL  AGRAWAL', 'SH. P C SHETH', 'SH. K S NATARAJAN', 
'SH. S N DAMLE', 'SH. A M FADIA']
['DR. K N M RAO', 'SH. IYER M. RAMASWAMY', 'SH. DILIP KANTI MAZUMDAR', 'SH. RAM CHANDRA NIGAM', 'SH. SUBRAHMANIAM VISWANATHAN', 'SH. SURESH KUMAR JERATH', 'SH. A Y SRINIVASAN', 'DR. S C GARG', 
'SH. CHANDRA PRAKASH SHARDA', 'SH. M P JAIN']
['SH. E S DWARKANATH', 'SH. MYSORE SHAMANNA  RAMACHANDRA', 'SH. SUBHASH CHANDER SINGHAL', 'SH. T T SINHA', 'SH. G R BHANDARI', 'SH. M P GOEL', 'SH. CHOKKANATHAPURAM SUBRAMANIAN  NATESAN', 'SH. 
V M PATEL', 'SH. BIJOY KUMAR AGARWALLA', 'SH. BAHADUR CHAND JAIN']
person αԋɱҽԃ αмєяιcαη    schedule 11.05.2020
comment
Да, оба ваших решения работают. Спасибо триллион. - person MITHU; 11.05.2020
comment
@MITHU добро пожаловать, не стесняйтесь принять мой ответ, поставив галочку рядом с ответом, если он вам помог. Вы также можете проголосовать, если хотите. - person αԋɱҽԃ αмєяιcαη; 11.05.2020