本篇博客使用 selenium 实现对简书官网的操作。
通过 selenium 执行 JS
selenium 打开网页之后,可以通过 JS 对页面进行修改,例如修改页面标题,代码如下:
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
opt = Options()
driver = webdriver.Chrome()
driver.get("http://www.jianshu.com")
js1 = "document.title='我的简书'"
driver.execute_script(js1)
js2 = "alert($('title').text())"
driver.execute_script(js2)
测试 JS 与 JQuery 代码在 selenium 访问简书时,都可以运行,但不是所有网站都可以执行 JQ 代码,需目标页面有加载 jquery 文件。
执行 JS 代码的方法为 execute_script ,可以在该方法要执行的 JS 代码中,增加 return 关键字,就可以返回 JS 的执行结果。
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
opt = Options()
driver = webdriver.Chrome()
driver.get("http://www.jianshu.com")
js1 = "$('title').text()"
ret1 = driver.execute_script(js1)
js2 = "return $('title').text()"
ret2 = driver.execute_script(js2)
print(ret1,ret2)
execute_script 方法还允许向 JS 传递参数,在 JS 中需要使用关键字 arguments 接收。
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
opt = Options()
driver = webdriver.Chrome()
driver.get("http://www.jianshu.com")
js1 = "document.title = arguments[0]"
ret1 = driver.execute_script(js1, ("我的简书",))
更多执行 JS 的效果,在后续博客进行学习。
selenium 实现简书搜索
通过开发者工具查看简书搜索框的 HTML 代码为:
<input
type="text"
name="q"
id="q"
value=""
autocomplete="off"
placeholder="搜索"
class="search-input"
data-mounted="1"
/>
搜索框可以通过 id="q" 进行定位。 搜索按钮的 HTML 代码如下:
<a class="search-btn" href="javascript:void(null)"
><i class="iconfont ic-search"></i
></a>
通过 class="search-btn" 进行定位。
基于上述内容,编写搜索页面的跳转代码如下。
from selenium import webdriver
from selenium.webdriver.chrome.options import Options
opt = Options()
driver = webdriver.Chrome()
driver.get("http://www.jianshu.com")
search_box = driver.find_element_by_id("q").send_keys("梦想橡皮擦")
click_btn = driver.find_element_by_class_name('search-btn').click()
selenium 隐式与显式等待
在 selenium 中存在显式与隐式两种等待方法,其中核心用到的第一个方法是:
driver.implicitly_wait(30)
implicitly_wait() 方法表示等待找到元素或者等待命令被完成,设置一次,整个程序都会受到影响,该方法只有一个参数,为等待时间,单位是秒。 注意:此方法不能设置 execute_async_script 的等待时间。
from selenium import webdriver
driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.get("http://www.jianshu.com")
container = driver.find_element_by_id("list-container")
print(container)
隐式等待会一直等待整个页面加载完成,相当于我们浏览网页时,浏览器不再加载为止。
如果希望显式的等待网页元素,可以使用下述代码
显示等待:执行自定义的程序判断条件,如果判断条件成立执行下一步,否则继续等待,直到超过设定的最长等待时间,然后抛出TimeoutError 异常。
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.implicitly_wait(10)
driver.get("http://www.jianshu.com")
container = WebDriverWait(driver,10).until(EC.presence_of_element_located((By.ID,'list-container')))
print(container)
在编写前优先导入了 3 个模块
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
其中用到的核心代码如下:
WebDriverWait(driver,10).until(EC.presence_of_element_located((By.ID,'list-container')))
接下来依次解释一下相关函数。
WebDriverWait 类的构造函数如下:
def __init__(self, driver, timeout, poll_frequency=POLL_FREQUENCY, ignored_exceptions=None)
其中参数含义为:
driver :WebDriver 对象实例;timeout :超时时间;poll_frequency :调用 until 或 until_not 中的方法的间隔时间,默认是 0.5 秒;ignored_exceptions :可忽略的异常,在调用 until 或 until_not 的过程中,如果出现元组内的异常,则不中断代码,继续等待,如果抛出的是元组外的异常,则中断代码,抛出异常。默认只有 NoSuchElementException 。
WebDriverWait 对象有两种等待方式,分别为 until ,until_not ,这两个方法的参数一致,如下所示:
method :在等待期间,每隔一段时间(poll_frequency )调用这个传入的方法,直到返回值不是 False;message :抛出 TimeoutError 时的错误提示。
其中可执行方法 method 参数,可以传递的值为 expected_conditions 模块中的各种条件,也可以传递 WebElement 的 is_displayed() 、is_enabled() 、is_selected() 方法,如果你想自己实现,注意一定要在类中编写 __call__ 方法。
expected_conditions 是 selenium 的一个模块,包含一系列可用于判断的条件,例如上述代码中使用的 presence_of_element_located ,表示判断某个元素是否被加载到了 HTML dom 树中。
expected_conditions 模块下也同样包含非常多的类,具体直接查看源码即可,传入的参数多数是一个元组类型的定位器( locator ),格式为 (by,path) ,例如 (By.ID,'list-container') ,其中 by 参数由 selenium.webdriver.common.by 模块提供。 By 类提供的属性有
ID = "id"
XPATH = "xpath"
LINK_TEXT = "link text"
PARTIAL_LINK_TEXT = "partial link text"
NAME = "name"
TAG_NAME = "tag name"
CLASS_NAME = "class name"
CSS_SELECTOR = "css selector"
selenium 采集京东图书
接下来用学到的一点点内容,采集一下京东图书,整体代码如下所示,其中 get_attribute 方法用于获取 WebElement 对象的属性值。
from selenium import webdriver
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
driver = webdriver.Chrome()
driver.get("https://book.jd.com/booktop/0-0-0.html?category=1713-0-0-0-10001-1#comfort")
locator = (By.XPATH, '//div[@class="mc"][1]/ul')
try:
ul = WebDriverWait(driver, 10).until(EC.presence_of_element_located(locator))
except TimeoutError as te:
print(te)
all_items = ul.find_elements_by_xpath('./li')
for item in all_items:
title = item.find_element_by_xpath('./div[2]/a').get_attribute('title')
author = item.find_element_by_xpath('./div[3]/dl[1]/dd/a[1]').get_attribute('title')
publisher = item.find_element_by_xpath('./div[3]/dl[2]/dd/a').text
price = item.find_element_by_xpath('./div[3]/dl[3]/dd/del').text
jd_price = item.find_element_by_xpath('./div[3]/dl[4]/dd/em').text
print(title,author,publisher,price,jd_price)
driver.quit()
订阅时间
今天是持续写作的第 276 / 365 天。 可以关注我,点赞我、评论我、收藏我啦。
更多精彩
👇👇👇扫码加入【78技术人】~ Python 事业部👇👇👇,源码也在这
|