浏览器抓取网页(Selenium强大的网络数据采集工具是怎样的?-八维教育)
优采云 发布时间: 2022-04-14 04:15浏览器抓取网页(Selenium强大的网络数据采集工具是怎样的?-八维教育)
Selenium 是一个强大的网络数据采集工具,最初是为网站自动化测试而开发的。近年来,它也被广泛用于获取准确的网站快照,因为它们直接在浏览器上运行。Selenium 可以让浏览器自动加载页面,获取需要的数据,甚至对页面进行截图,或者判断 网站 上的某些动作是否发生。
Selenium 没有自带浏览器,需要配合第三方浏览器使用。例如,如果您在 Firefox 上运行 Selenium,您可以直接看到一个 Firefox 窗口打开,转到 网站,然后执行您在代码中设置的操作。虽然这样更容易查看,但我更喜欢让程序在后台运行,所以我使用了一个名为 PhantonJS 的工具而不是真正的浏览器。
PhantomJS 是一个“无头”浏览器。它将 网站 加载到内存中并在页面上执行 JavaScript,但它不会向用户显示页面的图形界面。将 Selenium 和 PhantomJS 结合在一起,您可以运行一个非常强大的网络爬虫,它可以处理 cookie、JavaScript、标头以及您需要做的任何其他事情。
您可以从 PyPI 网站 下载 Selenium 库,或使用第三方管理器(如 pip)从命令行安装它。
PhantomJS 也可以从其官方 网站 下载。因为 PhantomJS 是一个成熟的(尽管是无头的)浏览器而不是 Python 库,所以它不需要像其他 Python 库那样安装,也不能用 pip 安装。
虽然有很多页面使用 Ajax 来加载数据(尤其是 Google),但我们发现了一个完全用 JavaScript 生成的页面,也是一个名为 SMS America 的 PWA 应用程序,用于测试我们的爬虫。此页面上的一些电话号码和短信都是由 JavaScript 生成的。如果我们传统的方法采集这个页面,我们只能获取加载前的页面,而我们真正需要的信息(Ajax执行后的页面)却无法获取。
Selenium 库是在 WebDriver 上调用的 API。WebDriver 有点像可以加载网站的浏览器,但也可以像BeautifulSoup 对象一样用于查找页面元素,与页面上的元素交互(发送文本、点击等),以及执行其他操作运行 Web Crawler 的操作。
以下代码获取 Ajax “墙”后面的内容:
import os
from dotenv import load_dotenv
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import WebDriverException
from config import logger_config
class TestWebDriver(object):
def __init__(self):
load_dotenv()
logger_name = 'Web Scraping to SMS America'
self._logger_write_file = logger_config.LoggingConfig().init_logging(logger_name)
self._chrome_path_file = os.getenv('CHROME_PATH')
def get_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").text
except (WebDriverException, UnboundLocalError) as e:
self._logger_write_file.error(f'处理 app-home 的时候出现错误,具体错误内容:{e},地址:{link}')
return False
finally:
driver.quit()
return get_content
def main(self):
link = "https://america.storytrain.info/home"
self.get_asn_content(link)
if __name__ == '__main__':
TestWebDriver().main()
以上代码使用了webDriver和Chrome浏览器的方式。首先,Chrome 库创建一个新的 Selenium WebDriver。首先,使用 WebDriver 加载页面,然后暂停执行 10 秒,然后查看页面以获取(希望已加载)内容。
根据您的 Chrome 安装位置,在创建新的 Chrome WebDriver 时,您需要在 Selenium 的 WebDriver 访问点中指定 Chrome 可执行文件的路径:
driver = webdriver.Chrome(executable_path=os.getenv('CHROME_PATH'))
由于Selenium升级到v4.0.0或以上,使用上述代码时会出现警告,所以我们重新修改代码如下:
import os
from dotenv import load_dotenv
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import WebDriverException
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
from config import logger_config
class TestWebDriver(object):
def __init__(self):
load_dotenv()
logger_name = 'Web Scraping to SMS America'
self._logger_write_file = logger_config.LoggingConfig().init_logging(logger_name)
self._chrome_path_file = os.getenv('CHROME_PATH')
def get_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").text
except (WebDriverException, UnboundLocalError) as e:
self._logger_write_file.error(f'处理 app-home 的时候出现错误,具体错误内容:{e},地址:{link}')
return False
finally:
driver.quit()
print(get_content)
return get_content
def main(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 的隐式等待。
隐式等待和显式等待的区别在于,隐式等待是在继续运行代码之前等待DOM中的某个状态发生(没有显式等待时间,但是有最大等待时间限制,只要它在时间限制内),而显式等待显式设置等待时间。在隐式等待中,DOM触发的状态是用expected_conditions定义的(这里导入后使用别名EC,是常用的缩写)。Selenium 库中有许多类型的元素被触发的预期条件,包括:
当然,大多数期望条件都要求您在使用它们之前指定要等待的目标元素。元素使用定位器指定。请注意,定位器与选择器不同(参见前面对选择器的介绍)。定位器是一种抽象查询语言,由 By 对象表示,可以在不同的情况下使用,包括创建选择器。
在下面的示例代码中,选择器用于查找类为 title-phone-number 的文本内容:
get_content = driver.find_element(By.CLASS_NAME, "title-phone-number").text
总结
这篇文章主要讲解了如何在Chrome浏览器中使用Python中的Selenium来获取JavaScript生成的内容,以及如何处理内容是否已经加载的相关问题。最后,它解释了 Selenium 如何选择热表面元素和其他相关内容。
有了上面的文章,我们应该可以处理一些JavaScript生成的页面内容了。