如何在 Python 中抓取 javascript 网站?

Posted

技术标签:

【中文标题】如何在 Python 中抓取 javascript 网站?【英文标题】:How to scrape a javascript website in Python? 【发布时间】:2020-12-24 22:56:02 【问题描述】:

我正在尝试抓取一个网站。我尝试使用两种方法,但都没有为我提供我正在寻找的完整网站源代码。我正在尝试从下面提供的网站 URL 中抓取新闻标题。

网址:“https://www.todayonline.com/”

这是我尝试过但失败的两种方法。

方法一:靓汤

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

方法 2:硒 + 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 

请帮忙。我尝试过抓取其他新闻网站,这要容易得多。谢谢。

【问题讨论】:

您尝试抓取的网站上的新闻数据是使用 JavaScript 获取的,服务器不会返回。但是在第一个示例中,您只获得了服务器返回的页面——请求和 BeautifulSoup 都不执行 JS。但是,您可以打开 Firefox (Chromium) DevTools 并查看哪些请求从服务器获取数据,然后尝试使用请求来模仿它们。这可能比尝试使用 BeautifulSoup 进行网页抓取更容易。 另见@politicalscientist 的回答。他完全按照我在第一条评论中描述的那样做。 【参考方案1】:

您尝试抓取的网站上的新闻数据是使用 JavaScript 从服务器获取的(这称为XHR -- XMLHttpRequest)。它是在页面加载或滚动时动态发生的。所以这个数据不会在服务器返回的页面内返回。

在第一个示例中,您只获得了服务器返回的页面——没有新闻,但是应该使用 JS 来获取它们。 requests 和 BeautifulSoup 都不能执行 JS。

但是,您可以尝试使用 Python 请求重现从服务器获取新闻标题的请求。执行以下步骤:

    打开浏览器的 DevTools(通常需要按 F12Ctrl+Shift+I kbd>),并查看从服务器获取新闻标题的请求。有时,它甚至比使用 BeautifulSoup 抓取网页更容易。这是屏幕截图(Firefox):

    复制请求链接(右键->复制->复制链接),并传递给requests.get(...)

    获取请求的.json()。它将返回一个易于使用的字典。为了更好地理解字典的结构,我建议使用pprint 而不是简单的打印。请注意,您必须在使用它之前执行from pprint import pprint

以下是从页面上的主要新闻中获取标题的代码示例:

import requests


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

如果要抓取标题下的一组新闻,则需要更改请求 URL 中news_feed/ 后面的数字(要获取它,您只需在 DevTools 中通过“news_feed”过滤请求并滚动新闻页面向下)。

有时网站可以防止僵尸程序(尽管您尝试抓取的网站没有)。在这种情况下,您可能还需要使用these steps。

【讨论】:

【参考方案2】:

我会建议你相当简单的方法,

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)

输出

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

此外,如果需要,您可以查看 XML 页面以获取更多信息。

附:在抓取任何网站之前始终检查合规性:)

【讨论】:

【参考方案3】:

收集包含 Javascript 的网页内容的方法有多种。

    selenium 与 Firefox 网络驱动程序一起使用 使用带有phantomJS 的无头浏览器 使用 REST 客户端或 python requests 库进行 API 调用

您必须先进行研究

【讨论】:

【参考方案4】:

您可以通过 API 访问数据(查看“网络”选项卡):


例如,

import requests
url = "https://www.todayonline.com/api/v3/news_feed/7"
data = requests.get(url).json()

【讨论】:

以上是关于如何在 Python 中抓取 javascript 网站?的主要内容,如果未能解决你的问题,请参考以下文章

用python抓取javascript生成的html

如何抓取 HTTPS javascript 网页

使用 Python 抓取网页动态内容(动态 HTML/Javascript 表格)

用于 javascript 生成内容的 Python 网页抓取

Python 使用 Selenium 和 Beautiful Soup 抓取 JavaScript

使用javascript屏幕延迟抓取网站[关闭]