本篇博客使用 selenium 实现对简书官网的操作。
通过 selenium 执行 JS
selenium 打开网页之后,可以通过 JS 对页面进行修改,例如修改页面标题,代码如下:
 from selenium import webdriverfrom selenium.webdriver.chrome.options import Options
opt = Options()  # 创建 chrome 参数对象
driver = webdriver.Chrome()
driver.get("http://www.jianshu.com")  # 打开简书
js1 = "document.title='我的简书'"driver.execute_script(js1)  # 执行JS代码
js2 = "alert($('title').text())"driver.execute_script(js2)  # 执行Jquery代码
# driver.quit()
       复制代码
 
测试 JS 与 JQuery 代码在 selenium 访问简书时,都可以运行,但不是所有网站都可以执行 JQ 代码,需目标页面有加载 jquery 文件。
执行 JS 代码的方法为 execute_script,可以在该方法要执行的 JS 代码中,增加 return  关键字,就可以返回 JS 的执行结果。
 from selenium import webdriverfrom selenium.webdriver.chrome.options import Options
opt = Options()  # 创建 chrome 参数对象
driver = webdriver.Chrome()
driver.get("http://www.jianshu.com")  # 打开简书
js1 = "$('title').text()"ret1 = driver.execute_script(js1) # 返回 None
js2 = "return $('title').text()"ret2 = driver.execute_script(js2) # 返回获取到的标题
print(ret1,ret2)
       复制代码
 
execute_script 方法还允许向 JS 传递参数,在 JS 中需要使用关键字 arguments 接收。
 from selenium import webdriverfrom selenium.webdriver.chrome.options import Options
opt = Options()  # 创建 chrome 参数对象
driver = webdriver.Chrome()
driver.get("http://www.jianshu.com")  # 打开简书
js1 = "document.title = arguments[0]"ret1 = driver.execute_script(js1, ("我的简书",))
# driver.quit()
       复制代码
 
更多执行 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 webdriverfrom selenium.webdriver.chrome.options import Options
opt = Options()  # 创建 chrome 参数对象
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() # 点击搜索按钮
# driver.quit()
       复制代码
 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 webdriverfrom selenium.webdriver.support.wait import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECfrom selenium.webdriver.common.by import By
driver = webdriver.Chrome()driver.implicitly_wait(10)
driver.get("http://www.jianshu.com")  # 打开简书
# container = driver.find_element_by_id("list-container") # 隐式等待# print(container)
container = WebDriverWait(driver,10).until(EC.presence_of_element_located((By.ID,'list-container')))print(container)
       复制代码
 
在编写前优先导入了 3 个模块
 from selenium.webdriver.support.wait import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECfrom 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)
       复制代码
 
其中参数含义为:
WebDriverWait 对象有两种等待方式,分别为 until,until_not,这两个方法的参数一致,如下所示:
其中可执行方法 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 webdriverfrom selenium.webdriver.support.wait import WebDriverWaitfrom selenium.webdriver.support import expected_conditions as ECfrom 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()
       复制代码
 订阅时间
今天是持续写作的第 <font color=red>276</font> / 365 天。可以<font color=#04a9f4>关注</font>我,<font color=#04a9f4>点赞</font>我、<font color=#04a9f4>评论</font>我、<font color=#04a9f4>收藏</font>我啦。
评论