Tabla de raspado y análisis de varias páginas (aspx)

Estoy tratando de raspar información sobre razas de galgos. Por ejemplo, quiero raspar http://www.gbgb.org.uk/RaceCard.aspx?dogName=Hardwick%20Serena . Esta página muestra todos los resultados para el perro Hardwick Serena, pero está dividida en varias páginas.

Al inspeccionar la página, se muestra debajo del botón ‘siguiente página’:

. 

Esperaba un enlace HTML, que pudiera usar para la próxima iteración del raspado, pero no tuve suerte. Una inspección adicional, al observar el tráfico de la red, muestra que el navegador envía una cadena horriblemente larga (¿con hash?) Para __VIEWSTATE, entre otras. ¿Es probable que proteja la base de datos?

Estoy buscando una manera de raspar todas las páginas de un perro, ya sea iterando sobre todas las páginas, o aumentando la longitud de la página para mostrar más de 100 líneas en la página 1. La base de datos subyacente es .aspx.

Estoy usando Python 3.5 y BeautifulSoup.

código actual:

  import requests from bs4 import BeautifulSoup url = 'http://www.gbgb.org.uk/RaceCard.aspx?dogName=Hardwick%20Serena' with requests.session() as s: s.headers['user-agent'] = 'Mozilla/5.0' r = s.get(url) soup = BeautifulSoup(r.content, 'html5lib') target = 'ctl00$ctl00$mainContent$cmscontent$DogRaceCard$btnFilter_input' data = { tag['name']: tag['value'] for tag in soup.select('input[name^=ctl00]') if tag.get('value') } state = { tag['name']: tag['value'] for tag in soup.select('input[name^=__]') } data.update(state) numberpages = int(str(soup.find('div', 'rgWrap rgInfoPart')).split(' ')[-2].split('>')[1].split('<')[0]) # for page in range(last_page + 1): for page in range(numberpages): data['__EVENTTARGET'] = target.format(page) #data['__VIEWSTATE'] = target.format(page) print(10) r = s.post(url, data=data) soup = BeautifulSoup(r.content, 'html5lib') tables = soup.findChildren('table') my_table = tables[9] rows = my_table.findChildren(['th', 'tr']) tabel = [[]] for i in range(len(rows)): cells = rows[i].findChildren('td') tabel.append([]) for j in range(len(cells)): value = cells[j].string tabel[i].append(value) table = [] for i in range(len(tabel)): if len(tabel[i]) == 16: del tabel[i][-2:] table.append(tabel[i]) 

En este caso, para cada página solicitada, se emite una solicitud POST con el parámetro codificado de url de formulario __EVENTTARGET & __VIEWSTATE :

  • __VIEWSTATE se puede extraer fácilmente de una etiqueta de input
  • __EVENTTARGET es diferente para cada página y el valor se pasa desde una función javacript para cada enlace de página, por lo que puede extraerlo con una expresión regular:

      2  

El script de python:

 from bs4 import BeautifulSoup import requests import re # extract data from page def extract_data(soup): tables = soup.find_all("div", {"class":"race-card"})[0].find_all("tbody") item_list = [ ( t[0].text.strip(), #date t[1].text.strip(), #dist t[2].text.strip(), #TP t[3].text.strip(), #StmHCP t[4].text.strip(), #Fin t[5].text.strip(), #By t[6].text.strip(), #WinnerOr2nd t[7].text.strip(), #Venue t[8].text.strip(), #Remarks t[9].text.strip(), #WinTime t[10].text.strip(), #Going t[11].text.strip(), #SP t[12].text.strip(), #Class t[13].text.strip() #CalcTm ) for t in (t.find_all('td') for t in tables[1].find_all('tr')) if t ] print(item_list) session = requests.Session() url = 'http://www.gbgb.org.uk/RaceCard.aspx?dogName=Hardwick%20Serena' response = session.get(url) soup = BeautifulSoup(response.content, "html.parser") # get view state value view_state = soup.find_all("input", {"id":"__VIEWSTATE"})[0]["value"] # get all event target values event_target = soup.find_all("div", {"class":"rgNumPart"})[0] event_target_list = [ re.search('__doPostBack\(\'(.*)\',', t["href"]).group(1) for t in event_target.find_all('a') ] # extract data for the 1st page extract_data(soup) # extract data for each page except the first for link in event_target_list[1:]: print("get page {0}".format(link)) post_data = { '__EVENTTARGET': link, '__VIEWSTATE': view_state } response = session.post(url, data=post_data) soup = BeautifulSoup(response.content, "html.parser") extract_data(soup)