Selenium是一个用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,就像真正的用户在操作一样,可以用其进行网页动态渲染页面的爬取。
支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。
1. 示例
### selenium的使用 ''' Selenium是一个用于Web应用程序测试的工具。 Selenium测试直接运行在浏览器中,就像真正的用户在操作一样。 支持的浏览器包括IE(7, 8, 9, 10, 11),Mozilla Firefox,Safari,Google Chrome,Opera等。 ''' ## 示例 from selenium import webdriver from selenium.webdriver.common.by import By 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() try: browser.get('https://www.baidu.com') input = browser.find_element_by_id('kw') input.send_keys('Python') input.send_keys(Keys.ENTER) wait = WebDriverWait(browser, 10) wait.until(ec.presence_of_element_located((By.ID, 'content_left'))) print(browser.page_source) print(browser.current_url) print(browser.get_cookies()) finally: browser.close()
2. 声明浏览器对象
## 声明浏览器对象 from selenium import webdriver # 声明1个chrome浏览器对象 browser1 = webdriver.Chrome() # 声明1个firefox浏览器对象 browser2 = webdriver.Firefox() # 声明1个edge浏览器对象 browser3 = webdriver.Edge() # 声明1个safari浏览器对象 browser4 = webdriver.Safari() # 声明1个phantonjs无界面浏览器对象 browser5 = webdriver.PhantomJS()
3. get方法访问页面
## 访问页面,get方法 from selenium import webdriver # 声明浏览器对象 browser = webdriver.Chrome() # 访问淘宝主页 browser.get('https://www.taobao.com') # 打印访问到的页面源码 print(browser.page_source) # 关闭浏览器 browser.close()
4. 查找节点
## 查找节点 ## element返回单个节点对象, ## elements返回多个节点对象的列表 # 1.根据id、class、name、text、tag等的值获取:find_element_by_id, # 2.通过css选择器获取:find_element_by_css_selector # 3.通过xpath方法获取:find_element_by_xpath from selenium import webdriver from selenium.webdriver.common.by import By browser = webdriver.Chrome() browser.get('https://www.taobao.com') input_1 = browser.find_element_by_id('q') input_2 = browser.find_element_by_css_selector('#q') input_3 = browser.find_element_by_xpath('//input[@id="q"]') # 查找节点的其他写法 input_other = browser.find_element(By.CSS_SELECTOR, '#q') # 查找多个节点,返回匹配到的对象的列表 elements = browser.find_elements(By.XPATH, '//*[contains(@class, "service-bd")]//li') print(type(elements), elements) print(input_1, input_2, input_3, input_other) print(type(input_1), type(input_2), type(input_3), type(input_other)) browser.close()
5. 节点间进行交互
## 节点交互 ## 输入内容send_keys ## 清空内容clear ## 触发点击click import time from selenium import webdriver browser = webdriver.Chrome() browser.get('https://www.taobao.com') input = browser.find_element_by_id('q') input.send_keys('电脑') time.sleep(2) input.clear() input.send_keys('手机') button = browser.find_element_by_xpath('//button[contains(@class, "btn-search")]') button.click() time.sleep(2) browser.close()
6. 动作链,鼠标拖拽,键盘按键等
## 动作链,鼠标拖拽,键盘按键等 from selenium import webdriver from selenium.webdriver import ActionChains browser = webdriver.Chrome() url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable' browser.get(url) # webDriver只能在一个页面上对元素识别和定位,对于frame/iframe表单内嵌页面上的元素无法直接定位,
# 此时就需要通过switch_to.frame()方法将当前定位的主题切换为iframe表单的内嵌页面中。 browser.switch_to.frame('iframeResult') drag = browser.find_element_by_id('draggable') drop = browser.find_element_by_id('droppable') # 声明对象 action = ActionChains(browser) # 调用drag_and_drop方法 action.drag_and_drop(drag, drop) # 执行刚刚调用的方法 action.perform() browser.close()
7. 执行JavaScript
## 执行JavaScript from selenium import webdriver browser = webdriver.Chrome() browser.get('https://www.mi.com/') browser.execute_script('window.scrollTo(0, document.body.scrollHeight)') browser.execute_script('alert("已到底部")')
8. 获取节点信息,如text,attribute等
## 获取节点信息 from selenium import webdriver browser = webdriver.Chrome() browser.get('https://www.taobao.com') s = browser.find_element_by_id('tb-beacon-aplus') print(type(s), s) # 获取s节点的src属性信息 print(s.get_attribute('src')) s2 = browser.find_element_by_class_name('site-nav-menu-hd') # 获取节点的文本信息 print(s2.text) # 获取节点的id print(s2.id) # 获取节点的标签名 print(s2.tag_name) # 获取节点基于页面的相对位置 print(s2.location) # 获取节点内容的大小,即占据页面的长度以及宽度 print(s2.size) browser.close()
9. 切换Frame
## 切换Frame # 网页中有一种iframe节点,iframe节点里的内容相当于页面的子页面,子页面内容结构和正常网页结构完全一致 # selenium打开页面时只能获取到父级Frame页面的内容,要想获取子页面内容,需要switch_to.frame()方法来切换页面 from selenium import webdriver from selenium.common import exceptions browser = webdriver.Chrome() url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable' browser.get(url) try: browser.find_element_by_id('droppable') except exceptions.NoSuchElementException: print('NO element...') # 切换frame browser.switch_to.frame('iframeResult') s = browser.find_element_by_id('droppable') print(s)
10. 延时等待
## 延时等待 ## 隐式等待,类似于time.sleep ## 显式等待,当检测到某个节点内容后即返回,推荐使用 # 隐式等待 from selenium import webdriver browser = webdriver.Chrome() browser.implicitly_wait(10) browser.get('https://www.taobao.com') input = browser.find_element_by_id('q') print(input.tag_name) browser.close() # 显式等待 from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC browser = webdriver.Chrome() browser.get('https://www.taobao.com') # 基于browser构建一个等待对象,等待最大时间为10s wait = WebDriverWait(browser, 10) # 等待10s时间内,如果页面出现id="q"节点时,则返回节点并且程序继续执行,否则抛出异常,程序结束 # presence_of_element_located中进行判断节点是否出现,传入一个元组 w = wait.until(EC.presence_of_element_located((By.ID, 'q'))) input = browser.find_element_by_id('q') print(w.id, input.tag_name) browser.close() ''' 其他等待条件说明: title_is 标题是某内容 title_contains 标题包含某内容 presence_of_element_located 节点加载出来(传入元组(By.ID, 'q')) visibility_of_element_located 节点可见,传入定位元组 visibility_of 节点对象可见,传入节点对象 presence_of_all_elements_located 所有节点加载出来 text_to_be_present_in_element 某个节点文本包含某文字 text_to_be_present_in_element_value 某个节点值包含某文字 text_to_be_available_amd_switch_to_it 加载并切换 invisibility_of_element_located 节点不可见 element_to_be_clickable 节点可点击 staleness_of 判断节点是否在DOM,可用于判断页面是否已经刷新 element_to_be_selected 节点可选择,传入节点对象 element_located_to_be_selected 节点可选择,传入节点定位元组 element_selection_state_to_be 传入节点对象及状态,相等返回True element_located_selection_state_to_be 传入定位元组及状态,相等返回True alert_is_present 是否出现警告 '''
11. 前进和后退
## 前进和后退 from selenium import webdriver import time browser = webdriver.Chrome() browser.get('https://www.baidu.com') browser.get('https://www.taobao.com') browser.get('https://www.zhihu.com') browser.get('https://www.mi.com') browser.back() browser.back() browser.forward() time.sleep(2) browser.close()
12. Cookies操作,获取、添加、删除等
## Cookies操作,获取、添加、删除 from selenium import webdriver browser = webdriver.Chrome() browser.get('https://www.taobao.com') print(len(browser.get_cookies()), browser.get_cookies()) browser.add_cookie({'name': 'name', 'domain': '.taobao.com', 'value': 'dfjld'}) print(len(browser.get_cookies()), browser.get_cookies()) browser.delete_all_cookies() print(len(browser.get_cookies()), browser.get_cookies()) browser.close()
13. 选项卡操作
## 选项卡处理 import time from selenium import webdriver browser = webdriver.Chrome() browser.get('https://www.baidu.com') # 新建选项卡 browser.execute_script('window.open()') print(browser.window_handles) # 切换选项卡 browser.switch_to_window(browser.window_handles[1]) browser.get('https://www.taobao.com') print(browser.current_url) browser.switch_to.window(browser.window_handles[0]) print(browser.current_url) browser.close()
14. 异常处理
## 异常处理 from selenium import webdriver from selenium.common.exceptions import NoSuchElementException, TimeoutException browser = webdriver.Chrome() try: browser.get('https://www.taobao.com') except TimeoutException: print('TIME OUT...') try: browser.find_element_by_id('qdfd') except NoSuchElementException: print('NO ELEMENT...') finally: browser.close()
15. selenium爬取jd商品信息实例代码
### selenium爬取jd商品信息 ### Author: dmr from pyquery import PyQuery as pq from selenium import webdriver from selenium.webdriver.support import expected_conditions as EC from selenium.webdriver.common.by import By from selenium.webdriver.support.wait import WebDriverWait from selenium.common.exceptions import TimeoutException from selenium.common.exceptions import StaleElementReferenceException from urllib.parse import quote import requests, time, pymongo def get_source_page(browser, keyword, page): ''' 判断当前页面是否加载完成并返回加载完成页面源码 :param page:页码 :return:页面源码 ''' wait = WebDriverWait(browser, 10) print('正在爬取第 %d 页' % page) try: url = 'https://search.jd.com/Search?enc=utf-8&keyword=' + quote(keyword) browser.get(url) # 拉到浏览器页面底部,获取当前页面所有的商品信息,防止操作过程中页面节点变化导致操作失败 browser.execute_script('window.scrollTo(0, document.body.scrollHeight)') time.sleep(2) # wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '#J_goodsList li.gl-item > div.gl-i-wrap'))) # 当page大于1时,进行页面跳转 if page > 1: # 获取当前跳转页面节点 page_input = wait.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#J_bottomPage .p-skip > input'))) # 获取跳转页面按键节点 submit = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '#J_bottomPage .p-skip > a'))) page_input.clear() page_input.send_keys(str(page)) submit.click() # 确保已完成页面跳转 wait.until(EC.text_to_be_present_in_element((By.CSS_SELECTOR, '#J_bottomPage .p-num > a.curr'), str(page))) # 确保页面商品信息加载完成 wait.until(EC.presence_of_all_elements_located((By.CSS_SELECTOR, '#J_goodsList li.gl-item > div.gl-i-wrap'))) print('第 %s 页面加载完成,可以进行获取源码...' % str(page)) return browser.page_source except TimeoutException or StaleElementReferenceException: # 如果出现错误,继续尝试爬取 print('出现错误,正在继续尝试。。。') get_source_page(browser, keyword, page) def get_data(html): ''' 提取网页源代码并进行解析获取想要爬取的内容 :return: ''' doc = pq(html) items = doc('#J_goodsList li > .gl-i-wrap').items() for item in items: yield { 'img': item('.p-img img').attr.src if item('.p-img img').attr.src else item('.p-img img').attr('data-lazy-img'), 'price': item('.p-price strong i').text(), 'title': item('.p-name.p-name-type-2 em').text(), 'commit': item('.p-commit strong a').text(), 'shop': item('.p-shop span a').text(), 'icons': item('.p-icons i').text(), } def save_to_mongodb(collection, data): for item in data: try: collection.insert_one(item) print("插入数据成功,数据内容为:", item) except: print("插入数据内容失败,数据内容为:", item) def main(browser, keyword, offset): html = get_source_page(browser, keyword, offset) if html: data = get_data(html) # 建立连接对象 client = pymongo.MongoClient(host='10.0.0.100', port=27017) # 指定数据库,如无则创建 db = client.jd # 指定集合,如无则创建 collection = db[keyword] # 保存到mongodb中 save_to_mongodb(collection, data) else: print('第%s页的页面源码加载有误,页面源码为:%s' % (offset, html)) if __name__ == '__main__': keyword = input("请输入商品信息关键字:") browser = webdriver.Chrome() for page in range(1, 101): main(browser, keyword, page) browser.close()