用 python selenium 爬简书,Python自动化领域之 Selenium WebDriver 学习第2篇
本篇博客使用 selenium 实现对简书官网的操作。
通过 selenium 执行 JS
selenium 打开网页之后,可以通过 JS 对页面进行修改,例如修改页面标题,代码如下:
from selenium import webdriver
from 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 webdriver
from 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 webdriver
from 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 webdriver
from 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 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 = 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 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 天。
可以关注我,点赞我、评论我、收藏我啦。
- 点赞
- 收藏
- 关注作者
评论(0)