python Selenium 和 PyAutoGUI合璧爬取网页攻略
前一段时间在做关于美国请愿网站的研究,需要爬取change.org这个请愿网站上每个请愿的信息。大致爬虫顺序是:先爬取每个标签下所有请愿的名字和具体网址,访问每个具体网址爬取请愿的发起时间、内容等信息。这里就需要用到电脑模拟点击加载按钮、快捷键下载网页到本地的操作,也就需要用到Selenium和PyAutoGUI这两个强大的工具。
网页页面和Selenium基本介绍
先要介绍一下网页的页面,让大家对代码和工具所应用到的场景有一个基本了解。change.org是美国一个社会企业,主要运营线上请愿的发起和传播,像最近BLM运动的很多请愿都来自change.org。一个请愿会有主要标签,比如下图的Racial Justice:
点击对应标签后就能看到标签下的请愿。但是网页只会显示10个左右,想要加载全部需要点几十次网页底部的”Load More“按钮,这就需要Selenium了:
我最先接触的是R的Selenium,后来转到Python,两个的基本思想框架是一样的,就是用到不同的包,语法有一点点不同,所以这里安装和基础运用就两个混着介绍了。首先是要按照Selenium一系列的配置:要根据你的系统(Windows, 苹果…)选对应的安装方法,根据你用的浏览器下载安装对应的驱动,安装JAVA环境,安装R或Python对应的包…挺繁琐的,但网上有很多非常详细的教程,这里我贴一些对我非常有用的以供参考:
整体准备(以R为例):
https://www.cnblogs.com/mxly/p/10156517.html
JAVA配置和Selenium下载:
https://blog.csdn.net/weixin_40628687/article/details/78971934
Chrome浏览器与驱动:
https://blog.csdn.net/huilan_same/article/details/51896672
Chrome驱动调用问题:
https://blog.csdn.net/weixin_42508908/article/details/85986029
其它浏览器驱动:
https://www.cnblogs.com/qiezizi/p/8632058.html
Windows用户变量与系统变量区别:
https://blog.csdn.net/sxhlovehmm/article/details/44274633
Selenium官方文档:
https://www.selenium.dev/documentation/en/
Python Selenium包使用:
https://www.browserstack.com/guide/python-selenium-to-run-web-automation-test
Python Selenium包官方文档:
https://selenium-python.readthedocs.io/
RSelenium包使用:
https://blog.csdn.net/weixin_40628687/article/details/78998740
https://www.computerworld.com/article/2971265/how-to-drive-a-web-browser-with-r-and-rselenium.html(这个非常详细!)
找到XPath路径的Chrome插件:
http://www.cnplugins.com/devtool/xpath-helper/
测试CSS和XPath语法的网站:
https://www.freeformatter.com/xpath-tester.html
这么多链接一下看很头疼,我的建议就是先看第一个链接,把基本安装一步步完成,遇到问题就在搜索引擎里搜,中文搜不到用英文搜,然后放到具体项目里实战,比如想实现一个目的就去学对应的语法,慢慢地就能学会了。话不多说,就从我的项目开始吧。
用Selenium点击按钮(这里用R语法,下面的PyAUTOgui用Python):
首先要找到按钮的XPath或CSS路径,可以借助插件,下面这个就是按钮的XPath路径:
//*[@class=\'col-xs-12 col-md-8 col-md-offset-2\']/button[@class=\'btn btn-big btn-full bg-brighter\']
要使用RSelenium的函数findElement先找到这个路径下的按钮然后用clickElement来操作这个点击:
loadmore <- remDr$findElement(using = \'xpath\', "//*[@class=\'col-xs-12 col-md-8 col-md-offset-2\']/button[@class=\'btn btn-big btn-full bg-brighter\']") loadmore$clickElement()
下面是全部代码:
library(RSelenium) library(risingMap) library(XML) library(rvest) ## 打开浏览器 remDr <- remoteDriver(browserName ="chrome") remDr$open() ## 先打开网页 url <-"https://www.change.org/petitions?selected=victories" remDr$navigate(url) setwd("D:/.../change/") #点击加载按钮 # find button # driver.findElement(By.xpath("//a[contains(text(),\'Next\')]")).click(); # click button pb <- txtProgressBar(0, 5000, style = 3,char= paste0(\'load\', \'|\')) i=1 for (i in 1:5000){ # loadmore <- remDr$findElement(using = \'xpath\', "//*[@class=\'js-load-more\']/button[@class=\'btn btn-full btn-big\']") loadmore <- remDr$findElement(using = \'xpath\', "//*[@class=\'col-xs-12 col-md-8 col-md-offset-2\']/button[@class=\'btn btn-big btn-full bg-brighter\']") loadmore$clickElement() # wait Sys.sleep(0.5) setTxtProgressBar(pb, i) }
上面代码里我还用到了Sys.sleep,这是害怕电脑频繁点使得网页识别并封掉我;此外还用到进度条,想知道自己点了多少次了。当页面加载完毕后,就可以直接爬或者把网页下载到本地用readlines函数。爬取对应信息的方法在我博客里给社团同学做的R语言爬虫分享里。
当然,不是所有按钮都像这个load more这么好点,有一个按钮的路径我大概找了半天,后来拜托实习的带教老师帮忙找到了。就是下图这个按钮:
它的问题在于:如果直接复制插件找到的路径,是根本找不到它的。
class那么长,全复制到代码里根本识别不出来,原因在于其中只有一个class属性是属于这个按钮的,那就是box。当用bos做测试后发现才能成功点击按钮。这里还需要注意一个问题,上图是我手动输入网址访问的页面,当使用自动化访问该网页后对应按钮的class属性可能还有变化,比如这个按钮在自动化测试时的class属性变成display-block,但这背后的原理是一样的:就是不要使用全部class属性。
PyAutoGUI基本介绍及安装:
这个工具用从这个博客文章和youtube视频入手去了解是最好的(我是找了很多技术文章才最终找到它们的/(ㄒoㄒ)/~~):
PyAutoGUI基本介绍
https://www.zachnielsen.org/introduction-to-selenium-and-pyautogui.html
在Jupyter安装并引入包时报module not found error错:
多种方法安装pyautoGUI:
Python如何安装下载下来的包:
用Annaconda安装的Jupyter导入包时报错:
这样总算把PyAutoGUI安装完成了,但接下来使用又会遇到很多困难。
PyAutoGUI操作:
我要做的是批量访问网页,按ctrl+s键把网页保存到移动硬盘上,网页文件名为对应的请愿名。看视频讲解是一回事,实操又是一回事:比如视频没有告诉我我要实现的这一操作具体每一步要怎么做:电脑模拟按快捷键时鼠标需要放在网页空白处,要改变chrome设置默认下载路径,要把输入法调成全英不然即使切换到英在对话框弹出来是还是中文输入法…反正困难很多,一个个克服就是了,下面贴上全部代码:
import pyautogui import time import pandas as pd from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC from selenium.common.exceptions import NoSuchElementException from selenium.common.exceptions import ElementClickInterceptedException from time import sleep #读取存储了所有网址的csv website=pd.read_csv(\'website.csv\',encoding=\'gbk\') #启动浏览器 path=\'C:/Program Files (x86)/Google/Chrome/Application/chromedriver.exe\' from selenium.webdriver import Chrome driver = Chrome(path) #开始模拟下载 for i in range(i,len(website)+1): url=website.iloc[:,1][i] driver.get(url) #use exception here for x in range(0, 8): # try 8 times try: # msg.send() # put your logic here button = driver.find_element_by_class_name("display-block") button.click() str_error = None except (ElementClickInterceptedException,NoSuchElementException): sleep(1) else: break time.sleep(5) pyautogui.click() # open \'Save as...\' to save html and assets pyautogui.hotkey(\'ctrl\', \'s\') time.sleep(1) pyautogui.typewrite(website.iloc[:,0][i] + \'.html\') time.sleep(1) pyautogui.press (\'enter\') time.sleep(4)
上面的代码我用到了try和except还有多次sleep是因为网页加载比较慢,一定要留出充分的时间,但即便是我重复了八次,还有一些没有加载成功。这样折腾了好几天终于把这个任务完成了。
BONUS:电脑可以模拟我自动操作了,那我可不可以放手出门了呢?
答案是可以哦。
推荐向日葵远程监控,在你的手机和电脑上安装对应软件,同时给电脑设置禁止睡眠,人在外面时想要看程序运行到哪一步时,就可以打开手机远程监控操作你的电脑哦。