selenium 介绍与使用
1 selenium 介绍
什么是 selenium?selenium 是 Python 的一个第三方库, 对外提供的接口可以操作浏览器, 然后让浏览器完成自动化的操作.
selenium 最初是一个自动化测试工具, 而爬虫中使用它主要是为了解决 requests 无法直接执行 JavaScript 代码的问题 selenium 本质是通过驱动浏览器, 完全模拟浏览器的操作, 比如跳转, 输入, 点击, 下拉 等, 来拿到网页渲染之后的结果, 可支持多种浏览器.
2 下载安装
下载驱动 http://npm.taobao.org/mirrors/chromedriver/2.35/
下载 chromdriver.exe 放到 python 安装路径的 scripts 目录中即可, 注意最新版本是 2.38, 并非 2.9
pip install selenium
3 使用
- from selenium import webdriver
- from time import sleep
- from selenium.webdriver.common.keys import Keys # 键盘上操作键的模块
- # 后面是你的浏览器驱动位置, 记得前面加 r'','r'是防止字符转义的
- driver = webdriver.Chrome()
- # 用 get 打开百度页面
- driver.get("http://www.baidu.com")
- # 查找页面的 "设置" 选项, 并进行点击
- driver.find_elements_by_link_text('设置')[0].click()
- sleep(2)
- # # 打开设置后找到 "搜索设置" 选项, 设置为每页显示 50 条
- driver.find_elements_by_link_text('搜索设置')[0].click()
- sleep(2)
- # 选中每页显示 50 条
- m = driver.find_element_by_id('nr')
- sleep(2)
- m.find_element_by_xpath('//*[@id="nr"]/option[3]').click()
- m.find_element_by_xpath('.//option[3]').click()
- sleep(2)
- # 点击保存设置
- driver.find_elements_by_class_name("prefpanelgo")[0].click()
- sleep(2)
- # 处理弹出的警告页面 确定 accept() 和 取消 dismiss()
- driver.switch_to.alert().accept()
- sleep(2)
- # 找到百度的输入框, 并输入 美女
- driver.find_element_by_id('kw').send_keys('美女')
- sleep(2)
- # 点击搜索按钮
- driver.find_element_by_id('su').click()
- # (或者在输入框输入之后直接 driver.send_keys(Keys.ENTER)表示按下回车键)
- sleep(2)
- # 在打开的页面中找到 "Selenium - 开源中国社区", 并打开这个页面
- driver.find_elements_by_link_text('美女_百度图片')[0].click()
- sleep(3)
- # 关闭浏览器
- driver.quit()
4 元素定位
- find_element_by_id()
- find_element_by_name()
- find_element_by_class_name()
- find_element_by_tag_name()
- find_element_by_link_text()
- find_element_by_partial_link_text()
- find_element_by_xpath()
- find_element_by_CSS_selector()
- # 这些都有对应的 find_elements_by... 相对应
- # 注意: find_elements_by... 拿到的是一个列表
find_element_by... 拿到的是一个 tag 对象
5 节点交互
Selenium 可以驱动浏览器来执行一些操作, 也就是说可以让浏览器模拟执行一些动作. 比较常见的用法有: 输入文字时用 send_keys()方法, 清空文字时用 clear()方法, 点击按钮时用 click()方法.
- from selenium import webdriver
- import time
- browser = webdriver.Chrome()
- browser.get('https://www.taobao.com')
- input = browser.find_element_by_id('q')
- input.send_keys('MAC') # 输入搜索词条
- time.sleep(1)
- input.clear() # 清除词条
- input.send_keys('IPhone')
- button = browser.find_element_by_class_name('btn-search')
- button.click() #点击搜索按钮
6 动作链
在上面的实例中, 一些交互动作都是针对某个节点执行的. 比如, 对于输入框, 我们就调用它的输入文字和清空文字方法; 对于按钮, 就调用它的点击方法. 其实, 还有另外一些操作, 它们没有特定的执行对象, 比如鼠标拖曳, 键盘按键等, 这些动作用另一种方式来执行, 那就是动作链. 比如, 现在实现一个节点的拖曳操作, 将某个节点从一处拖曳到另外一处, 可以这样实现:
- from selenium import webdriver
- from selenium.webdriver import ActionChains
- import time
- browser = webdriver.Chrome()
- url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable'
- browser.get(url)
- browser.switch_to.frame('iframeResult')
- source = browser.find_element_by_css_selector('#draggable')
- target = browser.find_element_by_css_selector('#droppable')
- actions = ActionChains(browser)
- # actions.drag_and_drop(source, target)
- actions.click_and_hold(source).perform() # 点击并且按住
- time.sleep(1)
- actions.move_to_element(target).perform() # 移动到 target 位置
- time.sleep(1)
- actions.move_by_offset(xoffset=50,yoffset=0).perform() # 从当前位置再沿 x 轴平移 50 个单位
- actions.release()
7 执行 JS 动作
对于某些操作, Selenium API 并没有提供. 比如, 下拉进度条, 它可以直接模拟运行 JavaScript, 此时使用 execute_script()方法即可实现, 代码如下:
- from selenium import webdriver
- browser = webdriver.Chrome()
- browser.get('https://www.jd.com/')
- browser.execute_script('window.scrollTo(0, document.body.scrollHeight)')
- browser.execute_script('alert("123")')
如何判断滚动条已经下拉到最后的位置了? 代码如下:
- from selenium import webdriver
- from time import sleep
- url = "https://movie.douban.com/typerank?type_name=恐怖&type=20&interval_id=100:90&action="
- path = "./phantomjs-2.1.1-windows/bin/phantomjs.exe"
- height_list = [] # 用来放每次的拖动滚动条后页面的最大高度
- browser = webdriver.PhantomJS(executable_path=path)
- browser.get(url)
- height_list.append(browser.execute_script("return document.body.scrollHeight")) # 放第一次拖动滚动条后页面的最大高度
- while 1:
- browser.execute_script("scroll(0,1000000)") # 拖动滚动条, 取值范围足够大
- sleep(1)
- check_height = browser.execute_script("return document.body.scrollHeight")
- # 获取每次拖动的文档高度
- if check_height == height_list[-1]: # 判断拖动滚动条后的最大高度与上一次的最大高度的大小, 相等表明到了最底部
- break
- height_list.append(check_height)
- print(height_list) # [1000, 2480, 4391, 6301, 8211, 10121, 12031, 13941, 15851, 17761, 19098]
8 延时等待
在 Selenium 中, get()方法会在网页框架加载结束后结束执行, 此时如果获取 page_source, 可能并不是浏览器完全加载完成的页面, 如果某些页面有额外的 Ajax 请求, 我们在网页源代码中也不一定能成功获取到. 所以, 这里需要延时等待一定时间, 确保节点已经加载出来. 这里等待的方式有两种: 一种是隐式等待, 一种是显式等待.
隐式等待:
当使用隐式等待执行测试的时候, 如果 Selenium 没有在 DOM 中找到节点, 将继续等待, 超出设定时间后, 则抛出找不到节点的异常. 换句话说, 当查找节点而节点并没有立即出现的时候, 隐式等待将等待一段时间再查找 DOM(在这段时间之内不会查找, n 秒之后再进行查找), 默认的时间是 0. 示例如下:
- from selenium import webdriver
- from selenium.webdriver import ActionChains
- from selenium.webdriver.common.by import By #按照什么方式查找, By.ID,By.CSS_SELECTOR
- from selenium.webdriver.common.keys import Keys #键盘按键操作
- from selenium.webdriver.support import expected_conditions as EC
- from selenium.webdriver.support.wait import WebDriverWait #等待页面加载某些元素
- browser=webdriver.Chrome()
- # 隐式等待: 在查找所有元素时, 如果尚未被加载, 则等 10 秒, 10 秒之后再一次查找
- browser.implicitly_wait(10)
- browser.get('https://www.baidu.com')
- input_tag=browser.find_element_by_id('kw')
- input_tag.send_keys('美女')
- input_tag.send_keys(Keys.ENTER)
- contents=browser.find_element_by_id('content_left') #没有等待环节而直接查找, 找不到则会报错
- print(contents)
- browser.close()
显示等待:
隐式等待的效果其实并没有那么好, 因为我们只规定了一个固定时间, 而页面的加载时间会受到网络条件的影响. 这里还有一种更合适的显式等待方法, 它指定要查找的节点, 然后指定一个最长等待时间. 如果在规定时间内加载出来了这个节点, 就返回查找的节点; 如果到了规定时间依然没有加载出该节点, 则抛出超时异常.
- from selenium import webdriver
- from selenium.webdriver import ActionChains
- from selenium.webdriver.common.by import By #按照什么方式查找, By.ID,By.CSS_SELECTOR
- from selenium.webdriver.common.keys import Keys #键盘按键操作
- from selenium.webdriver.support import expected_conditions as EC
- from selenium.webdriver.support.wait import WebDriverWait #等待页面加载某些元素
- browser=webdriver.Chrome()
- browser.get('https://www.baidu.com')
- input_tag=browser.find_element_by_id('kw')
- input_tag.send_keys('美女')
- input_tag.send_keys(Keys.ENTER)
- # 显式等待: 显式地等待某个元素被加载
- wait=WebDriverWait(browser,10)
- wait.until(EC.presence_of_element_located((By.ID,'content_left')))
- contents=browser.find_element(By.CSS_SELECTOR,'#content_left')
- print(contents)
- browser.close()
9 获取 tag 节点的信息
通过 page_source 属性可以获取网页的源代码, 接着就可以使用解析库 (如正则表达式, Beautiful Soup,pyquery 等) 来提取信息了.
不过, 既然 Selenium 已经提供了选择节点的方法, 返回的是 WebElement 类型, 那么它也有相关的方法和属性来直接提取节点信息, 如属性, 文本等. 这样的话, 我们就可以不用通过解析源代码来提取信息了, 非常方便.
- from selenium import webdriver
- from selenium.webdriver.common.by import By #按照什么方式查找, By.ID,By.CSS_SELECTOR
- from selenium.webdriver.support import expected_conditions as EC
- from selenium.webdriver.support.wait import WebDriverWait #等待页面加载某些元素
- browser=webdriver.Chrome()
- browser.get('https://www.amazon.cn/')
- wait=WebDriverWait(browser,10)
- wait.until(EC.presence_of_element_located((By.ID,'cc-lm-tcgShowImgContainer')))
- tag=browser.find_element(By.CSS_SELECTOR,'#cc-lm-tcgShowImgContainer img')
- # 获取标签属性,
- print(tag.get_attribute('src'))
- # 获取标签 ID, 位置, 名称, 大小(了解)
- print(tag.id)
- print(tag.location) # {
- 'x': 0, 'y': 133
- }
- print(tag.tag_name)
- print(tag.size) # {
- 'height': 1453, 'width': 661
- }
- browser.close()
phantomJs 介绍与使用
1 PhantomJS 介绍
PhantomJS 是一款无界面的浏览器, 其自动化操作流程和上述操作谷歌浏览器是一致的. 由于是无界面的, 为了能够展示自动化操作流程, PhantomJS 为用户提供了一个截屏的功能, 使用 save_screenshot("xxx.png")函数实现.
重点: selenium+phantomjs 就是爬虫终极解决方案: 有些网站上的内容信息是通过动态加载 JS 形成的, 所以使用普通爬虫程序无法回去动态加载的 JS 内容. 例如豆瓣电影中的电影信息是通过下拉操作动态加载更多的电影信息.
- from selenium import webdriver
- import time
- """
- phantomjs, 完完全全模拟浏览器访问 url, 期间没有可视化界面
- """
- time.sleep(1)
- bro = webdriver.PhantomJS(executable_path="./phantomjs-2.1.1-windows/bin/phantomjs.exe")
- bro.get("https://www.baidu.com/")
- time.sleep(2)
- text_input = bro.find_element_by_id("kw")
- value_btn = bro.find_element_by_id("su")
- text_input.send_keys("粪叉子")
- value_btn.click()
- time.sleep(2)
- JS = "window.scrollTo(0,document.body.scrollHeight)"
- bro.execute_script(JS)
- time.sleep(2)
- page_text = bro.page_source
- print(page_text)
- bro.quit() # 同 bro.close()
2 Google 无头浏览器
由于 PhantomJs 最近已经停止了更新和维护, 所以推荐大家可以使用谷歌的无头浏览器, 是一款无界面的谷歌浏览器.
- from selenium import webdriver
- import time
- from selenium.webdriver.Chrome.options import Options
- """
- 使用无头浏览器的基本配置
- """
- chorme_options = Options()
- chorme_options.add_argument("--headless")
- chorme_options.add_argument("--disable-gpu")
- time.sleep(1)
- bro = webdriver.Chrome(executable_path="./chromedriver.exe", chrome_options=chorme_options)
- bro.get("https://www.baidu.com/")
- time.sleep(1)
- text_input = bro.find_element_by_id("kw")
- value_btn = bro.find_element_by_id("su")
- text_input.send_keys("玛莎拉斯")
- value_btn.click()
- time.sleep(1)
- JS = "window.scrollTo(0,document.body.scrollHeight)"
- bro.execute_script(JS)
- time.sleep(1)
- page_text = bro.page_source
- print(page_text)
- bro.quit()
图片的懒加载技术
1 图片懒加载概念:
图片懒加载是一种网页优化技术. 图片作为一种网络资源, 在被请求时也与普通静态资源一样, 将占用网络资源, 而一次性将整个页面的所有图片加载完, 将大大增加页面的首屏加载时间. 为了解决这种问题, 通过前后端配合, 使图片仅在浏览器当前视窗内出现时才加载该图片, 达到减少首屏图片请求数的技术就被称为 "图片懒加载".
2 网站一般如何实现图片懒加载技术呢?
在网页源码中, 在 img 标签中首先会使用一个 "伪属性"(通常使用 src2,original......)去存放真正的图片链接而并非是直接存放在 src 属性中. 当图片出现到页面的可视化区域中, 会动态将伪属性替换成 src 属性, 完成图片的加载.
3 站长素材案例后续分析: 通过细致观察页面的结构后发现, 网页中图片的链接是存储在了 src2 这个伪属性中, 代码如下:
- from bs4 import BeautifulSoup
- import requests
- # 爬取站长回家图片链接 http://sc.chinaz.com/tupian/meinvtupian.html
- url = "http://sc.chinaz.com/tupian/meinvtupian.html"
- headers = {
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.109 Safari/537.36"
- }
- page = requests.get(url,headers=headers)
- page.encoding = "utf8"
- soup = BeautifulSoup(page.text,"lxml")
- div_box = soup.find_all("div",id="container")
- for pic_box in div_box:
- src = pic_box.find_all("img")
- for i in src:
- print(i.attrs["alt"])
- print(i.attrs["src"]) # 没有 src 属性, 直接报错
- print(i.attrs["src2"]) # src2 伪属性
来源: http://www.bubuko.com/infodetail-2976317.html