Jak zeskrobać witrynę javascript w Pythonie?

Sep 06 2020

Próbuję zeskrobać stronę internetową. Próbowałem użyć dwóch metod, ale obie nie zapewniają mi pełnego kodu źródłowego witryny, którego szukam. Próbuję wydobyć tytuły wiadomości z adresu URL podanego poniżej.

URL: „https://www.todayonline.com/”

Oto dwie metody, które wypróbowałem, ale zawiodły.

Metoda 1: Piękna zupa

tdy_url = "https://www.todayonline.com/"
page = requests.get(tdy_url).text
soup = BeautifulSoup(page)
soup  # Returns me a HTML with javascript text
soup.find_all('h3')

### Returns me empty list []

Metoda 2: Selen + BeautifulSoup

tdy_url = "https://www.todayonline.com/"

options = Options()
options.headless = True

driver = webdriver.Chrome("chromedriver",options=options)

driver.get(tdy_url)
time.sleep(10)
html = driver.page_source

soup = BeautifulSoup(html)
soup.find_all('h3')

### Returns me only less than 1/4 of the 'h3' tags found in the original page source 

Proszę pomóż. Próbowałem zeskrobać inne strony z wiadomościami i jest to o wiele łatwiejsze. Dziękuję Ci.

Odpowiedzi

2 politicalscientist Sep 06 2020 at 15:38

Możesz uzyskać dostęp do danych przez API (sprawdź zakładkę Sieć):


Na przykład,

import requests
url = "https://www.todayonline.com/api/v3/news_feed/7"
data = requests.get(url).json()
2 Noname Sep 06 2020 at 15:39

Istnieją różne sposoby gromadzenia zawartości strony internetowej zawierającej JavaScript.

  1. Używanie seleniumze sterownikiem internetowym Firefox
  2. Korzystanie z bezgłowej przeglądarki z phantomJS
  3. Wykonywanie wywołania API przy użyciu klienta REST lub requestsbiblioteki Python

Najpierw musisz przeprowadzić badania

2 MananGajjar Sep 06 2020 at 16:04

Zaproponuję dość proste podejście,

import requests
from bs4 import BeautifulSoup as bs

page = requests.get('https://www.todayonline.com/googlenews.xml').content
soup = bs(page)
news = [i.text for i in soup.find_all('news:title')]

print(news)

wynik

['DBS named world’s best bank by New York-based financial publication',
 'Russia has very serious questions to answer on Navalny - UK',
 "Exclusive: 90% of China's Sinovac employees, families took coronavirus vaccine - CEO",
 'Three militants killed after fatal attack on policeman in Tunisia',
.....]

W razie potrzeby możesz również sprawdzić stronę XML, aby uzyskać więcej informacji.

PS Zawsze sprawdź zgodność przed usunięciem jakiejkolwiek strony internetowej :)

2 DemianWolf Sep 06 2020 at 16:00

Dane wiadomości na stronie, którą próbujesz zeskrobać, są pobierane z serwera za pomocą JavaScript (nazywa się to XHR - XMLHttpRequest ). Dzieje się to dynamicznie, podczas ładowania lub przewijania strony. więc te dane nie są zwracane wewnątrz strony zwróconej przez serwer.

W pierwszym przykładzie otrzymujesz tylko stronę zwróconą przez serwer - bez nowości, ale z JS, który ma je pobierać. Ani żądania, ani BeautifulSoup nie mogą wykonywać JS.

Możesz jednak spróbować odtworzyć żądania pobierające tytuły wiadomości z serwera za pomocą żądań Pythona. Wykonaj następujące kroki:

  1. Otwórz DevTools swojej przeglądarki (zwykle musisz w tym celu nacisnąć F12lub Ctrl+ Shit+ I) i przyjrzyj się żądaniom, które otrzymują tytuły wiadomości z serwera. Czasami jest to nawet łatwiejsze niż skrobanie stron internetowych za pomocą BeautifulSoup. Oto zrzut ekranu (Firefox):
  1. Skopiuj link żądania (kliknij prawym przyciskiem myszy -> Kopiuj -> Kopiuj łącze) i przekaż go do requests.get(...).

  2. Uzyskaj .json()prośbę. Zwróci dykt, z którym łatwo się pracuje. Aby lepiej zrozumieć strukturę dyktowania, polecałbym użyć pprintzamiast prostego druku. Pamiętaj, że musisz to zrobić from pprint import pprintprzed użyciem.

Oto przykład kodu, który pobiera tytuły z głównych wiadomości na stronie:

import requests


nodes = requests.get("https://www.todayonline.com/api/v3/news_feed/7")\
        .json()["nodes"]
for node in nodes:
    print(node["node"]["title"])

Jeśli chcesz zeskrobać grupę wiadomości pod podpisem, musisz zmienić numer po news_feed/w adresie URL żądania (aby go uzyskać, wystarczy przefiltrować żądania według „news_feed” w DevTools i przewinąć stronę z wiadomościami w dół).

Czasami witryny internetowe są chronione przed botami (chociaż witryna, którą próbujesz zeskrobać, nie). W takich przypadkach może być konieczne wykonanie również tych czynności .