关于python自动保存静态网页

前言

网上找到一段保存静态网页的代码,不能完成跑通,记录下。

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from selenium import webdriver
import time
import win32api
import win32con

# 测试网址
news_url = "http://news.youth.cn/sz/201812/t20181218_11817816.htm"

# 打开另存为mhtml功能
options = webdriver.ChromeOptions()
options.add_argument('--save-page-as-mhtml')
# 设置chromedriver,并打开webdriver
driver = webdriver.Chrome(chrome_options=options)
driver.get(news_url)
# 模拟键盘操作
win32api.keybd_event(17, 0, 0, 0) # 按下ctrl
win32api.keybd_event(65, 0, 0, 0) # 按下a
win32api.keybd_event(65, 0, win32con.KEYEVENTF_KEYUP, 0) # 释放a
win32api.keybd_event(83, 0, 0, 0) # 按下s
win32api.keybd_event(83, 0, win32con.KEYEVENTF_KEYUP, 0) # 释放s
win32api.keybd_event(17, 0, win32con.KEYEVENTF_KEYUP, 0) # 释放ctrl
win32api.keybd_event(13, 0, 0, 0) # 按下enter
win32api.keybd_event(13, 0, win32con.KEYEVENTF_KEYUP, 0) # 释放enter
# 预估下载时间,后期根据实际网速调整

time.sleep(5)
# 关闭webdriver
driver.close()

这里面用到了selenium跟win32api、win32con,需要用pip安装selenium与pywin32方可调用。

selenium是自动化测试经常用到的一个模块,支持java与python,可使浏览器自动化操作,关于selenium的安装与基本使用,可以查看这篇文章
pywin32是用到windows系统自动化的模块,可以模拟键盘鼠标操作,模拟调用系统命令等。

过程

脚本作用是用chrome打开网址,设置chrome参数(保存单页面),再连续使用Ctrl+a、Ctrl+s、Enter,自动保存网页。

测试时发现脚本运行到弹出保存窗口时就不动了,未执行按下与释放Enter,于是先查找了下keybd_event的键盘对照表,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
键盘键与虚拟键码对照表

      字母和数字键 数字小键盘的键功能键 其它键
      键   键码   键   键码    键   键码    键    键码
      A   65   0   96     F1   112   Backspace    8
      B   66   1   97     F2   113   Tab       9
      C   67    2   98     F3   114   Clear      12
      D   68    3   99     F4   115   Enter      13
      E   69    4   100    F5   116   Shift      16
      F   70    5   101    F6   117   Control     17
      G   71    6   102    F7   118   Alt       18
      H   72    7   103     F8   119   Caps Lock    20
      I   73    8   104    F9   120   Esc       27
      J   74    9   105    F10  121   Spacebar    32
      K   75    *   106    F11  122   Page Up     33
      L   76    +   107    F12  123   Page Down    34
      M   77    Enter 108    --   --   End       35
      N   78    -   109    --   --    Home      36
      O   79    .   110    --   --    Left Arrow   37
      P   80    /   111    --   --    Up Arrow    38
      Q   81    --   --    --   --    Right Arrow   39
      R   82    --   --    --   --    Down Arrow    40
      S   83    --   --    --   --    Insert      45
      T   84    --   --    --   --    Delete      46
      U   85    --   --    --   --    Help       47
      V   86    --   --    --   --    Num Lock     144
      W   87    Window 91       
      X   88      
      Y   89      
      Z   90      
      0   48      
      1   49      
      2   50       
      3   51       
      4   52       
      5   53       
      6   54       
      7   55       
      8   56       
      9   57

测试后发现Enter键位没错,接下来怀疑是窗口焦点问题,可能是在弹出保存窗口时脚本有执行到Enter键,但并不是在保存窗口上执行,便查看pywin32的文档,最后找到win32gui可以获取最前窗口句柄,代码如下:

1
2
3
import win32gui
hwnd = win32gui.GetForegroundWindow()
print(win32gui.GetWindowText(hwnd))

在测试代码中插入上面代码,输出最前窗口名,果然在执行时窗口焦点都在Chrome上,Enter键未在保存窗口生效,那么就尝试主动设置焦点窗口吧,设置焦点窗口代码如下:

1
2
3
window = win32gui.FindWindow(None, '另存为')
win32gui.SetForegroundWindow(window)
print(win32gui.GetWindowText(window))

获取名为“另存为”的窗口名,并设置为最上层窗口。

继续插入测试代码,结果执行出错:

1
pywintypes.errer: (1400, 'SetForegroundWindow', '无效的窗口句柄。')

无法获取到”另存为”的窗口,无法,在programcreek下查找win32gui的示例代码,发现示例代友上很多地方都有加上time.sleep(0.1),于是乎又得到一个猜想:系统弹出保存框的时间比python执行按下Enter键的时间长,于是在测试脚本

1
win32api.keybd_event(13, 0, 0, 0)           # 按下enter

前加上

1
time.sleep(0.1)

继续执行脚本,发现还是不行,直到把0.1秒提到3秒,脚本才完全跑通。

结论

由于脚本在调用保存窗口后就马上输入按Enter的命令,而保存窗口此时其实还没起来,所以脚本停留在了中间。由此得win32api.keybd_event虽然能自动调动系统命令,但由于系统执行需要时间,并不是实时返回,所以要注意加上time.sleep()等待系统执行完成。

最后跑通的脚本:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
from selenium import webdriver
import time
import win32api
import win32con

# 测试网址
news_url = "http://news.youth.cn/sz/201812/t20181218_11817816.htm"

# 打开另存为mhtml功能
options = webdriver.ChromeOptions()
options.add_argument('--save-page-as-mhtml')
# 设置chromedriver,并打开webdriver
driver = webdriver.Chrome(chrome_options=options)
driver.get(news_url)
# 模拟键盘操作
win32api.keybd_event(17, 0, 0, 0) # 按下ctrl
win32api.keybd_event(65, 0, 0, 0) # 按下a
win32api.keybd_event(65, 0, win32con.KEYEVENTF_KEYUP, 0) # 释放a
win32api.keybd_event(83, 0, 0, 0) # 按下s
win32api.keybd_event(83, 0, win32con.KEYEVENTF_KEYUP, 0) # 释放s
win32api.keybd_event(17, 0, win32con.KEYEVENTF_KEYUP, 0) # 释放ctrl
time.sleep(3)
win32api.keybd_event(13, 0, 0, 0) # 按下enter
win32api.keybd_event(13, 0, win32con.KEYEVENTF_KEYUP, 0) # 释放enter
# 预估下载时间,后期根据实际网速调整

time.sleep(5)
# 关闭webdriver
driver.close()

脚本来源:利用selenium保存静态网页
示例查找:programcreek


- - END - -


腾讯云
0%