使用Selenium保存完整网页内容

14
我想知道保存Selenium访问网站时检索到的所有文件的最佳方法。换句话说,当Selenium访问http://www.google.com时,我想要保存HTML、JavaScript(包括在src标签中引用的脚本)、图像,并且可能包含在iframes中的内容。如何实现这一点?
我知道getHTMLSource()将返回主框架中body内的HTML内容,但如何扩展此方法以下载再次呈现该页面所需的完整文件集。
先感谢您的帮助!

你找到什么了吗? - Toolkit
动态内容部分非常棘手。也许可以使用ChromeDriver(在无头模式下)及其开发工具协议与网络统计面板进行交互。我不知道这是否包括iframe内容。 - Jorge Orpinel Pérez
我找到了如何使用Selenium和Headless Chrome来完成这个任务...虽然相当复杂,但我创建了一个小型的Python应用程序来处理它:https://github.com/jorgeorpinel/site-page-size-scrapper - Jorge Orpinel Pérez
5个回答

7
Selenium并不是为此而设计的,您可以选择以下两种方式:
  1. 使用getHtmlSource并解析生成的HTML以查找对外部文件的引用,然后将其下载并存储在Selenium之外。
  2. 使用其他工具而非Selenium来下载和存储网站的离线版本 - 如果进行搜索,我相信有很多工具可以完成此任务。例如,WGet可以执行递归下载(http://en.wikipedia.org/wiki/Wget#Recursive_download)。
您想使用Selenium的原因是什么?这是您的测试策略的一部分还是您只是想找一个能创建页面的离线副本的工具?

2
我们想要使用Selenium的原因是因为它可以解析JavaScript,这对于重建整个页面(包括广告流量)至关重要。 - Rick
1
在我的情况下,我想使用Selenium来完成下载,以提高速度。无论如何,我都必须将页面加载到Selenium和Chrome中,我宁愿不再执行所有HTTP请求,而只是保存当前已加载的内容。 - Seanny123
1
+1 - WGet证明是我所需的完美解决方案。基本上是调用一个Web URL(它是一个动态生成的PDF),并将结果保存为本地PDF。 - Bryan Larson
然而,虽然WGet可以下载站点的外部资源,但它无法处理现代站点上发生的嵌套资源调用,例如在检索有关浏览器的某些信息后加载另一个javascript的javascript。 - jcrs

4
Selenium唯一内置的下载源内容的方法是:最初的回答。
driver = webdriver.Chrome()
driver.get('www.someurl.com')
page_source = driver.page_source

但是这并不会下载所有的图片、CSS和JS脚本,就像你在网页上使用ctrl+s时一样。因此,您需要在导航到像Algorithmatic所述的网页之后模拟ctr+s键。
我制作了一个代码片段来展示如何做到这一点。 https://gist.github.com/GrilledChickenThighs/211c307edf8f828806c4bb4e4707b106
# Download entire webpage including all javascript, html, css of webpage. Replicates ctrl+s when on a webpage.

from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.keys import Keys

def save_current_page():      
    ActionChains(browser).send_keys(Keys.CONTROL, "s").perform()

你的要点404了,而且你的代码对我来说不起作用,即使运行也没有弹出Ctrl-S窗口。 - Nam G VU

1
如果您真的想使用Selenium,那么您可以模拟Ctrl+S保存页面,但是模拟按下Enter或更改要保存网页及其内容的位置则更加麻烦(也依赖操作系统)。
我曾经想用Selenium做同样的事情,但后来意识到我可以使用像wget这样的工具,而且我真的不需要只使用Selenium。所以我最终使用了wget,它非常强大,正好能满足我的需求。
以下是在Python脚本中使用wget的方法:
    import os
    # Save HTML
    directory = 'directory_to_save_webpage_content/'
    url = 'http://www.google.com'
    wget = "wget -p -k -P {} {}".format(directory, url)
    os.system(wget)

传递的参数只是为了使您能够在离线情况下查看页面,就像您仍在联机一样。
--page-requisites           -p   -- get all images needed to display page
--convert-links             -k   -- convert links to be relative
--directory-prefix          -P   -- specify prefix to save files to

2
但是wget无法执行JavaScript。 - Toolkit
我尝试了这个,但交互窗口只返回了一个1,我的目录中没有输出。 - geoJshaun

1
一个好用的工具是http://www.httrack.com/,Selenium没有提供任何相关API。如果你需要在Selenium测试用例中保存完整页面内容,也许可以将httrack作为命令行工具来执行。谢谢。

0

我通过下载外部资源(图片)并替换它们的src属性来创建这个程序。
假设我想将所有<img>标签中的图像保存到相对于当前页面的../images路径下。

~/site
~/site/pages/
~/site/pages/page1.html
~/site/pages/page2.html
~/site/images/
~/site/images/img_for_page1.png
~/site/images/img_for_page2.png

我使用requests模块下载图片。

# save_full_page.py

from selenium import webdriver
import requests

...  # open page you want to save

with open("replace_img_srcs.js", 'r') as file:
    replace_img_srcs_js = file.read()

save_dir = "/home/user/site"
save_to_file = "/home/user/site/pages/page1.html"
img_tags = driver.find_elements(By.TAG_NAME, "img")
for img_tag in img_tags:
    img_src = img_tag.get_attribute("src")
    r = requests.get(img_src, allow_redirects=True)
    img_filename = img_src.rsplit('/', 1)[1]
    open(save_dir + "/images/" + img_filename, 'wb').write(r.content)
    driver.execute_script(replace_img_srcs_js)  # see below
    with open(save_to_file, 'w') as f:
        f.write(driver.page_source)

这段代码编辑了src属性。我将它放在一个单独的文件中,以便能够看到语法高亮。如果您愿意,可以直接将其内容放置在driver.execute_script(...)中。

// replace_img_srcs.js

Array.prototype.slice.call(document.getElementsByTagName('img')).forEach(
 function(item) {
   var img_src = item.src;
   var img_filename = img_src.replace(/^.*[\\\/]/, '');
   var img_filename_urlencoded = encodeURIComponent(img_filename)  // because images may be named with encoded symbols
   item.src = item.src.replace(img_src, "../images/" + img_filename_urlencoded);
 }
)

现在我们已经保存了可自主使用的页面。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接