¿Cómo raspar un sitio web javascript en Python?

Sep 06 2020

Estoy intentando raspar un sitio web. He intentado utilizar dos métodos, pero ninguno de los dos me proporciona el código fuente completo del sitio web que estoy buscando. Estoy intentando extraer los títulos de las noticias de la URL del sitio web que se proporciona a continuación.

URL: "https://www.todayonline.com/"

Estos son los dos métodos que probé pero fallé.

Método 1: sopa hermosa

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 []

Método 2: Selenio + 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 

Por favor ayuda. He intentado raspar otros sitios web de noticias y es mucho más fácil. Gracias.

Respuestas

2 politicalscientist Sep 06 2020 at 15:38

Puede acceder a los datos a través de API (consulte la pestaña Red):


Por ejemplo,

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

Existen diferentes formas de recopilar el contenido de una página web que contiene Javascript.

  1. Usar seleniumcon el controlador web de Firefox
  2. Usando un navegador sin cabeza con phantomJS
  3. Hacer una llamada a la API usando un cliente REST o una requestsbiblioteca de Python

Primero tienes que investigar

2 MananGajjar Sep 06 2020 at 16:04

Le sugeriré el enfoque bastante simple,

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)

salida

['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',
.....]

Además, puede consultar la página XML para obtener más información si es necesario.

PD Siempre verifique el cumplimiento antes de eliminar cualquier sitio web :)

2 DemianWolf Sep 06 2020 at 16:00

Los datos de noticias del sitio web que está intentando extraer se obtienen del servidor mediante JavaScript (esto se llama XHR - XMLHttpRequest ). Está sucediendo dinámicamente, mientras la página se carga o se desplaza. por lo que estos datos no se devuelven dentro de la página devuelta por el servidor.

En el primer ejemplo, solo obtiene la página devuelta por el servidor, sin las noticias, pero con JS que se supone que las obtiene. Ni las solicitudes ni BeautifulSoup pueden ejecutar JS.

Sin embargo, puede intentar reproducir solicitudes que obtienen títulos de noticias del servidor con solicitudes de Python. Realice los siguientes pasos:

  1. Abra DevTools de su navegador (por lo general, debe presionar F12o Ctrl+ Shit+ Ipara eso) y observe las solicitudes que reciben títulos de noticias del servidor. A veces, es incluso más fácil que raspar la web con BeautifulSoup. Aquí hay una captura de pantalla (Firefox):
  1. Copie el enlace de la solicitud (haga clic con el botón derecho -> Copiar -> Copiar enlace) y páselo a requests.get(...).

  2. Obtener .json()la solicitud. Devolverá un dict con el que es fácil trabajar. Para comprender mejor la estructura del dictado, recomendaría usarlo en pprintlugar de una simple impresión. Tenga en cuenta que debe hacerlo from pprint import pprintantes de usarlo.

A continuación, se muestra un ejemplo del código que obtiene los títulos de las principales noticias de la página:

import requests


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

Si desea raspar un grupo de noticias debajo del título, debe cambiar el número después news_feed/en la URL de la solicitud (para obtenerlo, solo necesita filtrar las solicitudes por "news_feed" en DevTools y desplazarse hacia abajo en la página de noticias).

A veces, los sitios web tienen protección contra bots (aunque el sitio web que está intentando raspar no la tiene). En tales casos, es posible que también deba seguir estos pasos .