用 python selenium 爬简书,Python自动化领域之 Selenium WebDriver 学习第2篇

举报
梦想橡皮擦 发表于 2022/02/28 09:22:42 2022/02/28
【摘要】 本篇博客使用 selenium 实现对简书官网的操作。 通过 selenium 执行 JSselenium 打开网页之后,可以通过 JS 对页面进行修改,例如修改页面标题,代码如下:from selenium import webdriverfrom selenium.webdriver.chrome.options import Optionsopt = Options() # 创建 c...

本篇博客使用 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:调用 untiluntil_not 中的方法的间隔时间,默认是 0.5 秒;
  • ignored_exceptions:可忽略的异常,在调用 untiluntil_not 的过程中,如果出现元组内的异常,则不中断代码,继续等待,如果抛出的是元组外的异常,则中断代码,抛出异常。默认只有 NoSuchElementException

WebDriverWait 对象有两种等待方式,分别为 untiluntil_not,这两个方法的参数一致,如下所示:

  • method:在等待期间,每隔一段时间(poll_frequency)调用这个传入的方法,直到返回值不是 False;
  • message:抛出 TimeoutError 时的错误提示。

其中可执行方法 method 参数,可以传递的值为 expected_conditions 模块中的各种条件,也可以传递 WebElementis_displayed()is_enabled()is_selected() 方法,如果你想自己实现,注意一定要在类中编写 __call__ 方法。

expected_conditionsselenium 的一个模块,包含一系列可用于判断的条件,例如上述代码中使用的 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 天。
可以关注我,点赞我、评论我、收藏我啦。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。