Toon posts:

Python and beautifulsoup4 met dopostback probleem

Pagina: 1
Acties:

Vraag


  • sp_mike
  • Registratie: November 2016
  • Laatst online: 23-03 14:18
Ik heb een redelijk simpel Python script om beursinformatie op te halen. Ik ben een beginner met Python maar dit loopt prima:

code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
from urllib.request import urlopen
from bs4 import BeautifulSoup
html = urlopen('https://www.guruwatch.nl/adviezen/default.aspx').read()
soup = BeautifulSoup(html, 'lxml')
table = soup.find('table',{'class':'ContentTable'})

rows = table.find_all('tr')

for row in rows:
data = row.find_all('td')

if (len(data) > 0):
    cell = data[0]
    print(cell.text)
    cell = data[1]
    print(cell.text)
    cell = data[2]
    print(cell.text)
    cell = data[3]
    print(cell.text)
    cell = data[4]
    print(cell.text)
    cell = data[5]
    print(cell.text)


Dit pakt netjes de eerste pagina van de tabel en leest de data uit.van: https://www.guruwatch.nl/adviezen/default.aspx
Als ik, handmatig, op "volgende" klik wordt dit uitgevoerd:

code:
1
javascript:__doPostBack('ctl00$ctl00$ContentPlaceHolder1$RightContent$ListAdviezen$cmdNext','')


Is er een manier om dit te automatiseren zodat ik alle data uit kan lezen? Ik las dat het wellicht met "Selenium" maar ik begrijp niet helemaal hoe dat in mijn situatie werkt.

Uiteindelijk wil ik het geautomatiseerd gaan draaien vanaf mijn Synology

Beste antwoord (via sp_mike op 10-01-2022 19:32)


  • DHH
  • Registratie: Augustus 2014
  • Laatst online: 23-03 21:55
Selenium lijkt me inderdaad de makkelijkste optie hiervoor. Het lijkt erop dat Selenium nieuw voor je is, dus ik heb geprobeerd in onderstaand voorbeeld zo veel mogelijk comments te schrijven om e.e.a. te verduidelijken, maar geef het gerust aan als je vragen hebt.

Om het voorbeeld te kunnen gebruiken heb je de geckodriver nodig, welke je hier kan downloaden: https://github.com/mozilla/geckodriver/releases (onderaan de pagina). I.g.v. Windows, pak de .zip uit en sla de .exe op in dezelfde folder als je script (of verwijs bij 'driver = webdriver.Firefox('<gecko-driver-path>') naar de juiste locatie.

Andere browsers zouden ook moeten werken, maar dan zal je even moeten zoeken naar de geckodriver voor de desbetreffende browser.


Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import time

from selenium import webdriver
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

MAX_WAIT = 10

def deal_with_cookies(driver):
    # Zoals je waarschijnlijk gemerkt hebt, moet je cookies accepteren om door te kunnen gaan. 
    # De cookie-wall wordt (met enige vertraging) geladen in een iframe
    # We wachten met het laden tot de iframe beschikbaar is
    element = WebDriverWait(driver, MAX_WAIT).until(EC.presence_of_element_located((By.XPATH, '//*[@id="gdpr-consent-notice"]')))
    driver.switch_to.frame(element)
    # Vervolgens zoeken we de button en klikken we op accepteren
    button = WebDriverWait(driver, MAX_WAIT).until(EC.element_to_be_clickable((By.XPATH, '//button[@id="save"]')))
    # Meestal gebruik je button.click() echter werkte dit in dit geval niet. Geen idee waarom, maar ENTER werkt wel, 
    # verschilt per site/button
    button.send_keys(Keys.ENTER)
    # Terug naar de oorspronkelijke frame met de bruikbare informatie
    driver.switch_to.default_content()

def click_volgende(driver):
    # D.m.v. de browser inspector kan je het element opzoeken. Dit kan o.m. via Xpath, id of name. 
    # Dit element heeft geen 'name', dus ik gebruik 'id'
    button = driver.find_element_by_id('ctl00_ctl00_ContentPlaceHolder1_RightContent_ListAdviezen_cmdNext')
    button.click()

def get_table_data(driver):
    # Nu halen we de tabel met class_name 'ContentTable' op. 
    # Vervolgens zoeken we alle table rows ('tr') in deze tabel en printen we de text per table row.
    # Je zou natuurlijk ook per table row kunnen zoeken naar de onderliggende 'td' voor de content per cell, 
    # maar dat mag je zelf doen :)
    start_time = time.time()
    try:
        table = driver.find_element_by_class_name('ContentTable')
        rows = table.find_elements_by_tag_name('tr')
        print([row.text for row in rows])  # of laadt in een dict / dataframe / database / whatever 
    except (AssertionError, WebDriverException) as e:
        if time.time() - start_time > MAX_WAIT:
            print("Unable to find element, ending script")
            raise e
        time.sleep(0.5)


def main():
    driver = webdriver.Firefox()
    driver.get('https://www.guruwatch.nl/adviezen/default.aspx')
    deal_with_cookies(driver)
    # in dit geval laad ik als voorbeeld pagina's 1 t/m 3, dit wil je misschien aanpassen naar alle pagina's. 
    # maar daar kom je vast wel uit 
    for page in range(1,4):
        print(f"Scraping page {page}.")
        get_table_data(driver)
        click_volgende(driver)
        # Ik laat 5 seconden tussen elke pagina, om wat tijd te geven om de pagina 
        # te laden en de website niet teveel te belasten.
        time.sleep(5)
    driver.quit()

if __name__ == "__main__":
    main()


Mocht je de smaak te pakken krijgen, kijk dan ook altijd even of de website toestaat dat je deze 'crawlt' en of er restricties zijn. Vaak kan je dit vinden op <site>/robots.txt.

Guruwatch heeft geen robots.txt, maar Tweakers bijv. wel: https://tweakers.net/robots.txt, voor meer informatie hierover zie https://developers.google.../robots/create-robots-txt.

Alle reacties


  • thlst
  • Registratie: Januari 2016
  • Niet online
Misschien kun je in de developer tools van je browser zien welke requests worden gemaakt als je op Volgende klikt

  • sp_mike
  • Registratie: November 2016
  • Laatst online: 23-03 14:18
Deze:

code:
1
https://iex.blueconic.net/DG/DEFAULT/rest/rpc/759?referer=https://www.guruwatch.nl/adviezen/default.aspx&bcsessionid=4d4f6ce6-c353-4141-bacd-204e0972fb55&bctempid=&overruleReferrer=&time=2022-01-08T12:30:02+01:00&ts=1641641402958


Helpt dit?

Acties:
  • Beste antwoord
  • 0Henk 'm!

  • DHH
  • Registratie: Augustus 2014
  • Laatst online: 23-03 21:55
Selenium lijkt me inderdaad de makkelijkste optie hiervoor. Het lijkt erop dat Selenium nieuw voor je is, dus ik heb geprobeerd in onderstaand voorbeeld zo veel mogelijk comments te schrijven om e.e.a. te verduidelijken, maar geef het gerust aan als je vragen hebt.

Om het voorbeeld te kunnen gebruiken heb je de geckodriver nodig, welke je hier kan downloaden: https://github.com/mozilla/geckodriver/releases (onderaan de pagina). I.g.v. Windows, pak de .zip uit en sla de .exe op in dezelfde folder als je script (of verwijs bij 'driver = webdriver.Firefox('<gecko-driver-path>') naar de juiste locatie.

Andere browsers zouden ook moeten werken, maar dan zal je even moeten zoeken naar de geckodriver voor de desbetreffende browser.


Python:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
import time

from selenium import webdriver
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait

MAX_WAIT = 10

def deal_with_cookies(driver):
    # Zoals je waarschijnlijk gemerkt hebt, moet je cookies accepteren om door te kunnen gaan. 
    # De cookie-wall wordt (met enige vertraging) geladen in een iframe
    # We wachten met het laden tot de iframe beschikbaar is
    element = WebDriverWait(driver, MAX_WAIT).until(EC.presence_of_element_located((By.XPATH, '//*[@id="gdpr-consent-notice"]')))
    driver.switch_to.frame(element)
    # Vervolgens zoeken we de button en klikken we op accepteren
    button = WebDriverWait(driver, MAX_WAIT).until(EC.element_to_be_clickable((By.XPATH, '//button[@id="save"]')))
    # Meestal gebruik je button.click() echter werkte dit in dit geval niet. Geen idee waarom, maar ENTER werkt wel, 
    # verschilt per site/button
    button.send_keys(Keys.ENTER)
    # Terug naar de oorspronkelijke frame met de bruikbare informatie
    driver.switch_to.default_content()

def click_volgende(driver):
    # D.m.v. de browser inspector kan je het element opzoeken. Dit kan o.m. via Xpath, id of name. 
    # Dit element heeft geen 'name', dus ik gebruik 'id'
    button = driver.find_element_by_id('ctl00_ctl00_ContentPlaceHolder1_RightContent_ListAdviezen_cmdNext')
    button.click()

def get_table_data(driver):
    # Nu halen we de tabel met class_name 'ContentTable' op. 
    # Vervolgens zoeken we alle table rows ('tr') in deze tabel en printen we de text per table row.
    # Je zou natuurlijk ook per table row kunnen zoeken naar de onderliggende 'td' voor de content per cell, 
    # maar dat mag je zelf doen :)
    start_time = time.time()
    try:
        table = driver.find_element_by_class_name('ContentTable')
        rows = table.find_elements_by_tag_name('tr')
        print([row.text for row in rows])  # of laadt in een dict / dataframe / database / whatever 
    except (AssertionError, WebDriverException) as e:
        if time.time() - start_time > MAX_WAIT:
            print("Unable to find element, ending script")
            raise e
        time.sleep(0.5)


def main():
    driver = webdriver.Firefox()
    driver.get('https://www.guruwatch.nl/adviezen/default.aspx')
    deal_with_cookies(driver)
    # in dit geval laad ik als voorbeeld pagina's 1 t/m 3, dit wil je misschien aanpassen naar alle pagina's. 
    # maar daar kom je vast wel uit 
    for page in range(1,4):
        print(f"Scraping page {page}.")
        get_table_data(driver)
        click_volgende(driver)
        # Ik laat 5 seconden tussen elke pagina, om wat tijd te geven om de pagina 
        # te laden en de website niet teveel te belasten.
        time.sleep(5)
    driver.quit()

if __name__ == "__main__":
    main()


Mocht je de smaak te pakken krijgen, kijk dan ook altijd even of de website toestaat dat je deze 'crawlt' en of er restricties zijn. Vaak kan je dit vinden op <site>/robots.txt.

Guruwatch heeft geen robots.txt, maar Tweakers bijv. wel: https://tweakers.net/robots.txt, voor meer informatie hierover zie https://developers.google.../robots/create-robots-txt.

  • sp_mike
  • Registratie: November 2016
  • Laatst online: 23-03 14:18
Enorm bedankt, ik ga het vanavond gelijk proberen.
Het werkt. Ga het nog even finetunen maar ontzettend bedankt!

[Voor 38% gewijzigd door sp_mike op 10-01-2022 19:32]



Tweakers maakt gebruik van cookies

Tweakers plaatst functionele en analytische cookies voor het functioneren van de website en het verbeteren van de website-ervaring. Deze cookies zijn noodzakelijk. Om op Tweakers relevantere advertenties te tonen en om ingesloten content van derden te tonen (bijvoorbeeld video's), vragen we je toestemming. Via ingesloten content kunnen derde partijen diensten leveren en verbeteren, bezoekersstatistieken bijhouden, gepersonaliseerde content tonen, gerichte advertenties tonen en gebruikersprofielen opbouwen. Hiervoor worden apparaatgegevens, IP-adres, geolocatie en surfgedrag vastgelegd.

Meer informatie vind je in ons cookiebeleid.

Sluiten

Toestemming beheren

Hieronder kun je per doeleinde of partij toestemming geven of intrekken. Meer informatie vind je in ons cookiebeleid.

Functioneel en analytisch

Deze cookies zijn noodzakelijk voor het functioneren van de website en het verbeteren van de website-ervaring. Klik op het informatie-icoon voor meer informatie. Meer details

janee

    Relevantere advertenties

    Dit beperkt het aantal keer dat dezelfde advertentie getoond wordt (frequency capping) en maakt het mogelijk om binnen Tweakers contextuele advertenties te tonen op basis van pagina's die je hebt bezocht. Meer details

    Tweakers genereert een willekeurige unieke code als identifier. Deze data wordt niet gedeeld met adverteerders of andere derde partijen en je kunt niet buiten Tweakers gevolgd worden. Indien je bent ingelogd, wordt deze identifier gekoppeld aan je account. Indien je niet bent ingelogd, wordt deze identifier gekoppeld aan je sessie die maximaal 4 maanden actief blijft. Je kunt deze toestemming te allen tijde intrekken.

    Ingesloten content van derden

    Deze cookies kunnen door derde partijen geplaatst worden via ingesloten content. Klik op het informatie-icoon voor meer informatie over de verwerkingsdoeleinden. Meer details

    janee