使用python /硒保存完整的网页(包括CSS,图像)

时间:2018-12-11 17:18:32

标签: python selenium web-crawler bioinformatics

我正在使用Python / Selenium将遗传序列提交到在线数据库,并希望保存返回的完整结果页面。以下是使我获得所需结果的代码:

from selenium import webdriver

URL = 'https://blast.ncbi.nlm.nih.gov/Blast.cgi?PROGRAM=blastx&PAGE_TYPE=BlastSearch&LINK_LOC=blasthome'
SEQUENCE = 'CCTAAACTATAGAAGGACAGCTCAAACACAAAGTTACCTAAACTATAGAAGGACAGCTCAAACACAAAGTTACCTAAACTATAGAAGGACAGCTCAAACACAAAGTTACCTAAACTATAGAAGGACAGCTCAAACACAAAGTTACCTAAACTATAGAAGGACA' #'GAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGA'
CHROME_WEBDRIVER_LOCATION = '/home/max/Downloads/chromedriver' # update this for your machine

# open page with selenium
# (first need to download Chrome webdriver, or a firefox webdriver, etc)
driver = webdriver.Chrome(executable_path=CHROME_WEBDRIVER_LOCATION)
driver.get(URL)
time.sleep(5)

# enter sequence into the query field and hit 'blast' button to search
seq_query_field = driver.find_element_by_id("seq")
seq_query_field.send_keys(SEQUENCE)

blast_button = driver.find_element_by_id("b1")
blast_button.click()
time.sleep(60)

到那时,我有一个页面,可以手动单击“另存为”,并获取一个本地文件(带有image / js资产的相应文件夹),该文件可让我在本地查看整个返回的页面(减去内容向下滚动页面动态生成的,这很好)。我以为有一种简单的方法可以在python / selenium中模仿此“另存为”功能,但是还没有找到。用于保存下面页面的代码仅保存html,而不会给我留下一个看起来像在Web浏览器中一样的本地文件,图像等。

content = driver.page_source
with open('webpage.html', 'w') as f:
    f.write(content)

我也找到了this question/answer on SO,但是被接受的答案只是弹出了“另存为”框,并且没有提供一种单击它的方法(正如两个评论者所指出的那样)

有没有一种简单的方法可以使用python将[整页]另存为?理想情况下,我更喜欢使用硒的答案,因为硒使爬网部分非常简单,但是如果有更好的工具可以使用此库,我愿意使用其他库。或者,也许我只需要指定要在代码中下载的所有图像/表,就没有模拟右键单击“另存为”功能的捷径吗?

更新-詹姆斯回答的后续问题 因此,我运行了James的代码以生成page.html(及相关文件),并将其与手动单击另存为得到的html文件进行了比较。通过James脚本保存的page.html非常好,并且具有我所需的一切,但是在浏览器中打开时,它还会显示很多额外的格式化文本,这些文本隐藏在手动保存的页面中。请参阅附件的屏幕截图(左侧是手动保存的页面,右侧是脚本保存的页面,带有额外的格式化文本)。 enter image description here

这对我来说尤其令人惊讶,因为James脚本保存的页面原始html似乎表明这些字段仍应隐藏。参见例如下面的html,在两个文件中看起来都一样,但是有争议的文本仅出现在由James脚本保存的页面上的浏览器呈现页面中:

<p class="helpbox ui-ncbitoggler-slave ui-ncbitoggler" id="hlp1" aria-hidden="true">
These options control formatting of alignments in results pages. The
default is HTML, but other formats (including plain text) are available.
PSSM and PssmWithParameters are representations of Position Specific Scoring Matrices and are only available for PSI-BLAST. 
The Advanced view option allows the database descriptions to be sorted by various indices in a table.
</p>

知道为什么会这样吗?

4 个答案:

答案 0 :(得分:4)

这不是一个完美的解决方案,但是它将为您提供所需的大部分东西。您可以通过解析html并将所有已加载的文件(图像,css,js等)下载到相同的相对路径来复制“另存为完整网页(完整)”的行为。

由于跨源请求被阻止,大多数javascript无法正常工作。但是内容看起来(大部分)是相同的。

这使用requests保存加载的文件,使用lxml解析html,并使用os进行路径维护。

from selenium import webdriver
import chromedriver_binary
from lxml import html
import requests
import os

driver = webdriver.Chrome()
URL = 'https://blast.ncbi.nlm.nih.gov/Blast.cgi?PROGRAM=blastx&PAGE_TYPE=BlastSearch&LINK_LOC=blasthome'
SEQUENCE = 'CCTAAACTATAGAAGGACAGCTCAAACACAAAGTTACCTAAACTATAGAAGGACAGCTCAAACACAAAGTTACCTAAACTATAGAAGGACAGCTCAAACACAAAGTTACCTAAACTATAGAAGGACAGCTCAAACACAAAGTTACCTAAACTATAGAAGGACA' 
base = 'https://blast.ncbi.nlm.nih.gov/'

driver.get(URL)
seq_query_field = driver.find_element_by_id("seq")
seq_query_field.send_keys(SEQUENCE)
blast_button = driver.find_element_by_id("b1")
blast_button.click()

content = driver.page_source
# write the page content
os.mkdir('page')
with open('page/page.html', 'w') as fp:
    fp.write(content)

# download the referenced files to the same path as in the html
sess = requests.Session()
sess.get(base)            # sets cookies

# parse html
h = html.fromstring(content)
# get css/js files loaded in the head
for hr in h.xpath('head//@href'):
    if not hr.startswith('http'):
        local_path = 'page/' + hr
        hr = base + hr
    res = sess.get(hr)
    if not os.path.exists(os.path.dirname(local_path)):
        os.makedirs(os.path.dirname(local_path))
    with open(local_path, 'wb') as fp:
        fp.write(res.content)

# get image/js files from the body.  skip anything loaded from outside sources
for src in h.xpath('//@src'):
    if not src or src.startswith('http'):
        continue
    local_path = 'page/' + src
    print(local_path)
    src = base + src
    res = sess.get(hr)
    if not os.path.exists(os.path.dirname(local_path)):
        os.makedirs(os.path.dirname(local_path))
    with open(local_path, 'wb') as fp:
        fp.write(res.content)  

您应该有一个名为page的文件夹,其中包含一个名为page.html的文件,其中包含您要保存的内容。

答案 1 :(得分:3)

如您所述,Selenium无法与浏览器的上下文菜单交互以使用Save as...,因此,您可以使用pyautogui之类的外部自动化库。

pyautogui.hotkey('ctrl', 's')
time.sleep(1)
pyautogui.typewrite(SEQUENCE + '.html')
pyautogui.hotkey('enter')

此代码通过其键盘快捷键Save as...打开CTRL+S窗口,然后按Enter将网页及其资产保存到默认下载位置。该代码还将文件命名为序列,以便为其赋予唯一名称,尽管您可以针对用例进行更改。如果需要,您可以通过使用Tab和箭头键进行一些额外的操作来另外更改下载位置。

在Ubuntu 18.10上测试;根据您的操作系统,您可能需要修改发送的组合键。


完整代码,其中还添加了条件等待以提高速度:

import time
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.expected_conditions import visibility_of_element_located
from selenium.webdriver.support.ui import WebDriverWait
import pyautogui

URL = 'https://blast.ncbi.nlm.nih.gov/Blast.cgi?PROGRAM=blastx&PAGE_TYPE=BlastSearch&LINK_LOC=blasthome'
SEQUENCE = 'CCTAAACTATAGAAGGACAGCTCAAACACAAAGTTACCTAAACTATAGAAGGACAGCTCAAACACAAAGTTACCTAAACTATAGAAGGACAGCTCAAACACAAAGTTACCTAAACTATAGAAGGACAGCTCAAACACAAAGTTACCTAAACTATAGAAGGACA' #'GAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGAGAAGA'

# open page with selenium
# (first need to download Chrome webdriver, or a firefox webdriver, etc)
driver = webdriver.Chrome()
driver.get(URL)

# enter sequence into the query field and hit 'blast' button to search
seq_query_field = driver.find_element_by_id("seq")
seq_query_field.send_keys(SEQUENCE)

blast_button = driver.find_element_by_id("b1")
blast_button.click()

# wait until results are loaded
WebDriverWait(driver, 60).until(visibility_of_element_located((By.ID, 'grView')))

# open 'Save as...' to save html and assets
pyautogui.hotkey('ctrl', 's')
time.sleep(1)
pyautogui.typewrite(SEQUENCE + '.html')
pyautogui.hotkey('enter')

答案 2 :(得分:0)

受上述FThompson的回答启发,我想到了以下工具,该工具可以为给定的页面网址下载完整/完整的html(请参阅:https://github.com/markfront/SinglePageFullHtml

更新-遵循Max的建议,以下是使用该工具的步骤:

  1. 克隆项目,然后运行maven进行构建:
$> git clone https://github.com/markfront/SinglePageFullHtml.git

$> cd ~/git/SinglePageFullHtml
$> mvn clean compile package
  1. 在目标文件夹中找到生成的jar文件:SinglePageFullHtml-1.0-SNAPSHOT-jar-with-dependencies.jar

  2. 在命令行中运行jar,例如:

$> java -jar .target/SinglePageFullHtml-1.0-SNAPSHOT-jar-with-dependencies.jar <page_url>
  1. 结果文件名将带有前缀“ FP”,后跟页面URL的哈希码,文件扩展名为“ .html”。可以在任何一个文件夹“ / tmp”中找到(可以找到通过System.getProperty(“ java.io.tmp”)。否则,请尝试在您的主目录或Java中的System.getProperty(“ user.home”)中找到它。

  2. 结果文件将是一个庞大的独立HTML文件,其中包含原始html源引用的所有内容(css,javascript,图像等)。

答案 3 :(得分:-2)

我建议您尝试sikulix,它是一个基于图像的自动化工具,可用于操作PC OS中的任何小部件,它支持python语法并可以在命令行中运行,这也许是解决ur的最简单方法问题。 您需要做的就是给它截图,然后用python自动化脚本(带有OS.system(“ xxxx”)或子进程...)调用sikulix脚本。