当前位置: 首页 > Web前端 > JavaScript

爬虫系列:使用Selenium在Python中执行Javascript

时间:2023-03-27 16:12:21 JavaScript

SeleniumSelenium是一个强大的网络抓取工具,最初是为网站的自动化测试而开发的。近年来,它也被广泛用于对网站进行准确的快照,因为它们可以直接在浏览器上运行。Selenium允许浏览器自动加载页面,获取所需的数据,甚至对页面进行截图,或者判断网站上是否发生了某些操作。Selenium本身没有浏览器,需要配合第三方浏览器使用。例如,如果您在Firefox上运行Selenium,您会看到一个Firefox窗口打开,转到该网站,并执行您在代码中设置的操作。虽然这样看效果更好,但我更喜欢让程序在后台运行,所以我使用了一个叫做PhantonJS的工具,而不是真正的浏览器。PhantomJS是一个“headles”浏览器。它会将网站载入内存并在页面上执行JavaScript,但不会向用户显示网页的图形界面。结合Selenium和PhantomJS,你可以运行一个非常强大的网络爬虫,它可以处理cookie、JavaScript、标头,无论你需要做什么。您可以从PyPI网站下载Selenium库,或使用pip等第三方管理器从命令行安装它。PhantomJS也可以从其官网下载。因为PhantomJS是一个成熟的(尽管是无头的)浏览器而不是Python库,所以它不需要像其他Python库一样安装,也不能用pip安装。虽然有很多页面使用Ajax加载数据(尤其是Google),但是我们找到了一个页面,它全部由JavaScript生成,也是一个PWA应用程序,应用程序名称为SMSAmerica,来测试我们的爬虫。本页面部分电话号码和短信内容均由JavaScript生成。如果我们用传统的方式来抓取这个页面,只能获取到加载前的页面,而无法抓取到我们真正需要的信息(Ajax执行后的页面)。Selenium库是一个在WebDriver上调用的API。WebDriver有点像加载网站的浏览器,但它也可以像BeautifulSoup对象一样用于查找页面元素、与页面上的元素交互(发送文本、单击等),以及执行其他操作以运行web爬虫。下面的代码可以获取Ajax“墙”后面的内容:importosfromdotenvimportload_dotenvfromseleniumimportwebdriverfromselenium.webdriver.common.byimportByfromselenium.webdriver.support.uiimportWebDriverWaitfromselenium.webdriver.supportimportexpected_conditionsasECfromselenium。common.exceptionsimportWebDriverExceptionfromconfigimportlogger_configclassTestWebDriver(object):def__init__(self):load_dotenv()logger_name='WebScrapingtoSMSAmerica'self._logger_write_file=logger_config.LoggingConfig().init_logging(logger_name)self._chrome_path_file=os.getenv('CHROME_PATH')defget_asn_content(self,link):driver=webdriver.Chrome(executable_path=os.getenv('CHROME_PATH'))driver.get(link)try:WebDriverWait(driver,10).until(EC.presence_of_all_elements_located((By.ID,"prefixes")))get_content=driver.find_element(By.TAG_NAME,"app-home").textexcept(WebDriverException,UnboundLocalError)ase:self._logger_write_file.error(f'处理app-home时发生错误,具体错误内容:{e},地址:{link}')returnFalsefinally:driver.quit()returnget_contentdefmain(self):link="https://america.storytrain.info/home"self.get_asn_content(link)if__name__=='__main__':TestWebDriver().main()上面的代码使用了webDriver和Chrome浏览器的方式,首先,Chrome库新建一个SeleniumWebDriver,先用WebDriver加载页面,然后暂停执行10秒,然后检查页面获取(希望已加载)内容根据您的Chrome安装位置,在创建新的ChromeWebDriver时,您需要在Selenium的WebDriver访问点中指定Chrome可执行文件的路径:driver=webdriver.Chrome(executable_path=os.getenv('CHROME_PATH'))由于Selenium升级到v4.0.0以上,使用上面的代码会出现警告,所以我们重新修改代码如下:WebDriverWait来自selenium.webdriver。支持importexpected_conditionsasECfromselenium.common.exceptionsimportWebDriverExceptionfromseleniumimportwebdriverfromselenium.webdriver.chrome.serviceimportServicefromwebdriver_manager.chromeimportChromeDriverManagerfromconfigimportlogger_configclassTestWebDriver(object):def__init__(self):load_dotenv()logger_name='Web抓取SMSAmerica'self._logger_write_file=logger_config.LoggingConfig().init_logging(logger_name)self._chrome_path_file=os.getenv('CHROME_PATH')defget_asn_content(self,link):driver=webdriver.Chrome(service=Service(ChromeDriverManager().install()))driver.get(link)try:WebDriverWait(driver,10).until(EC.presence_of_all_elements_located((By.CLASS_NAME,"home-page-card-container")))get_content=driver.find_element(By.CLASS_NAME,"title-phone-number").textexcept(WebDriverException,UnboundLocalError)ase:self._logger_write_file.error(f'处理app-home时发生错误,具体报错内容:{e},地址:{link}')最后返回False:driver.quit()print(get_content)returnget_contentdefmain(self):link="https://america.storytrain.info/home"self.get_asn_content(link)if__name__=='__main__':TestWebDriver().main()如果程序配置正确,几分钟后上面的程序会显示如下结果:7743186342这个方法虽然有效,但是效率不够高,在处理大型网站时可能还是会出问题。页面的加载时间是不确定的,取决于服务器某毫秒的负载,以及不断变化的网络速度。虽然此页面可能只需要两秒多一点的时间来加载,但我们设置了十秒的等待时间以确保页面完全加载。一种更有效的方法是让Selenium不断检查元素是否存在以确定页面是否完全加载,如果页面加载成功则执行程序的其余部分。以下程序检查页面是否完全加载了类为home-page-card-container的页面的内容:WebDriverWait(driver,10).until(EC.presence_of_all_elements_located((By.CLASS_NAME,"home-page-card-container")))程序中引入了一些新的模块,最重要的是WebDriverwait和expected_conditions,这两个模块的组合构成了Selenium的隐式等待(implicitwait)。隐式等待和显式等待的区别是:隐式等待是等待DOM中某个状态发生,然后再继续运行代码(没有显式等待时间,但是有最大等待时间限制,只要它在时间限制内),而显式等待显式设置等待时间。在隐式等待中,DOM触发的状态由expected_conditions定义(这里导入后使用的别名EC,是常用的缩写)。Selenium库中元素触发的预期条件有很多,包括:弹出提示框、元素被选中(如文本框)、页面标题改变、某文本显示在页面或某个元素在DOM中变得可见,或者某个元素从DOM中消失。当然,大多数expect条件要求您在使用前指定要等待的目标元素。元素用定位符指定。请注意,定位器与选择器不同(请参阅前面对选择器的介绍)。Locator是一种抽象的查询语言,用By对象表示,可以在不同的场合使用,包括创建选择器。在下面的示例代码中,选择器用于查找类title-phone-number的文本内容:get_content=driver.find_element(By.CLASS_NAME,"title-phone-number").text它解释了如何在Python配合Chrome浏览器获取JavaScript生成的内容,以及如何处理内容是否已经加载的相关问题。最后解释了Selenium如何选择热表面元素等相关内容。通过上面的文章,我们应该可以处理一些JavaScript生成的页面内容了。