[转]爬虫 selenium + phantomjs / chrome
目录
selenium 模块
Web自动化测试工具, 可运行在浏览器,根据指定命令操作浏览器, 必须与第三方浏览器结合使用
安装
sudo pip3 install selenium
phantomjs 浏览器
无界面浏览器(无头浏览器), 在内存中进行页面加载,高效
安装
windows
下载对应安装包,将文件放到python安装目录的Scripts目录下
Linux
下载, 解压到任意路径
chromedriver 接口
性质完全同 phantomjs
下载地址 : 这里
安装
- 查看本机Chrome浏览器版本(设置-帮助-关于Google Chrome)
- 下载对应版本的chromedriver
- 拷贝到python安装目录的Scripts目录下
对比两个接口
chromedriver 比 phantomjs 性能好, 在 windows下更适合用 chromedriver
phantomjs 更适合用在 无界面环境下. 比如 linux 中, 且 phantomjs 多进程下性能下降严重
而且 phantomjs 很不稳定
整合使用
基本实例
简单实例 - 访问百度
# 导入接口
from selenium import webdriver # 创建 PhantomJS 浏览器对象
driver = webdriver.PhantomJS()
# 发送请求
driver.get('http://www.baidu.com/')
# 查看截图
driver.save_screenshot('百度.png')
# 关闭当前页
driver.close()
# 关闭浏览器
driver.quit()
稍微复杂的实例 - 百度输入跳转
# _*_ coding:utf-8 _*_ import time
# 导入接口
from selenium import webdriver # 创建 PhantomJS 浏览器对象
driver = webdriver.PhantomJS() # 发送请求
driver.get('http://www.baidu.com/') # 向搜索框 ( id=kw ) 输入"初音未来"
driver.find_element_by_id('kw').send_keys('初音未来') # 点击 百度一下 按钮 ( id=su )
driver.find_element_by_id('su').click()
# driver.find_element_by_class_name('btn self-btn bg s_btn btn_h btnhover') time.sleep(2) # 加载需要点时间 # 查看截图
driver.save_screenshot('miku.png') # 查看响应内容
html = driver.page_source
print(html) # 类似于 res = request.get().text() # 关闭当前页
driver.close() # 关闭浏览器
driver.quit()
特殊实例 - qq 邮箱登录
qq 邮箱页面是使用的 ifram子框架 (两个页面的嵌套页面) . 普通的方式是不行的
from selenium import webdriver
import time browser = webdriver.PhantomJS()
browser.get('https://mail.qq.com/') # 切换到ifram子框架(网页中又嵌套了一个网页)
login_frame = browser.find_element_by_id('login_frame')
browser.switch_to_frame(login_frame) # 输入qq号 密码 点击登录按钮
uname = browser.find_element_by_xpath('//*[@id="u"]')
uname.send_keys('') pwd = browser.find_element_by_xpath('//*[@id="p"]')
pwd.send_keys('') login = browser.find_element_by_xpath('//*[@id="login_button"]')
login.click() time.sleep(2)
browser.save_screenshot('login.png')
常用属性方法
导入
from selenium import webdriver
创建 phantomjs 浏览器对象
driver = webdriver.PhantomJS()
可选参数 executable_path
driver = webdriver.PhantomJS(executable_path="/xxxx")
可以指定 phantomjs 的路径, 如果已经放在 python 的 script 中就不用这样设置了.
因此推荐解压后放置在 python 的 script 中 ( 因为环境变量设置了 )
创建 chrome 浏览器对象
driver = webdriver.Chrome()
可选参数 executable_path 同上
可选参数 option
设置谷歌浏览器隐藏页面
options = webdriver.ChromeOptions()
* 方法1 :options.add_argument('--headless')
* 方法2 :options.set_headless()
browser = webdriver.Chrome(options=options)
browser.get('http://www.baidu.com/')
发请求
driver.get('http://www.baidu.com/')
查看源码
html = driver.page_source
print(html) # 类似于 res = request.get().text()
源码中搜索字符串
可以是文本值也可以是属性值
html = driver.page_source
res = html.find('字符串')
返回值
-1 未找到
其他 找到
关闭当前页面
driver.close()
关闭浏览器
driver.quit()
定位节点
单节点查找
推荐使用 xpath
xpath 可以直接检查中定位标签后复制即可. 是最为精准的方式
# 利用标签的属性
driver.find_element_by_id('')
driver.find_element_by_name('')
driver.find_element_by_class_name('') # 上面都没有的话可以用 xpath
driver.find_element_by_xpath('')
多节点查找
driver.find_elements_by_xxxxxxx('')
for ele in [节点对象列表]:
print(ele.text)
节点查找实例
from selenium import webdriver # 创建浏览器对象
browser = webdriver.PhantomJS()
browser.get('https://www.qiushibaike.com/text/') # 单元素查找
div = browser.find_element_by_class_name('content') # 多元素查找
divs = browser.find_elements_by_class_name('content')
for div in divs:
# text是获取当前节点对象中所有文本内容(所有节点)
print(div.text)
print('*' * 50)
节点操作
ele.text
拿到节点的内容 (包括后代节点的所有内容)
driver.find_element_by_id('').text
ele.send_keys("")
搜索框赋值
driver.find_element_by_id('kw').send_keys("初音未来")
ele.click()
点击标签
driver.find_element_by_id('su').click()
ele.get_attribute("")
获取属性值
# 获取元素标签的内容
att01 = a_href.get_attribute('textContent')
text_01 = a_href.text # # 获取元素内的全部HTML
att02 = a_href.get_attribute('innerHTML') # # 获取包含选中元素的HTML
att03 = a_href.get_attribute('outerHTML') # 获取该元素的标签类型
tag01 = a_href.tag_name
其他操作
不请求图片模式
只需要如下设置则不会请求图片, 会加快效率
代码 - 设置 chromedriver 不加载图片
chrome_opt = webdriver.ChromeOptions()
prefs = {"profile.managed_default_content_settings.images": 2}
chrome_opt.add_experimental_option("prefs", prefs)
查看截图
因为是在内存中的处理, 且无头浏览器也没办法看到具体的页面
使用此方法可以查看回传的截图
driver.save_screenshot('百度.png')
切换子框架
此操作主要作用与 ifram子框架 的互相切换使用
iframe = driver.find_element_by_xxx('')
driver.switch_to_frame(节点对象)
执行 JS 代码
execute_script 方法来执行 js 代码
browser.execute_script(
'window.scrollTo(0,document.body.scrollHeight)'
)
实例解析 - 京东商品爬取
页面分析
爬取京东商品
模拟操作搜索框输入查询商品后点击搜索
将返回页面的商品列表进行爬取
京东的页面展示机制中有配合 ajax 的请求
初始页面的提供了 30 个页面数据, 然后通过滑轮往下在发起 ajax 的请求剩下的30个
准备工作
URL 地址 https://www.jd.com/
搜索框节点 //*[@id="key"]
搜索按钮 //*[@id="search"]/div/div[2]/button
商品信息节点对象列表 //*[@id="J_goodsList"]/ul/li
爬虫代码
from selenium import webdriver
import time class JdSpirder(object):
def __init__(self, key):
self.browser = webdriver.PhantomJS()
self.url = 'https://www.jd.com/'
self.key = key # 获取商品页面
def get_page(self):
self.browser.get(self.url)
# 找节点
self.browser.find_element_by_xpath('//*[@id="key"]').send_keys(self.key)
self.browser.find_element_by_xpath('//*[@id="search"]/div/div[2]/button').click()
time.sleep(2)
self.parse_page() # 解析页面
def parse_page(self):
# 把下拉菜单拉到底部,执行JS脚本
self.browser.execute_script(
'window.scrollTo(0,document.body.scrollHeight)'
)
time.sleep(1)
# 匹配所有商品节点对象列表
li_list = self.browser.find_elements_by_xpath('//*[@id="J_goodsList"]/ul/li')
for li in li_list:
li_info = li.text.split('\n')
if li_info[0][0:2] == '每满':
price = li_info[1]
name = li_info[2]
commit = li_info[3]
market = li_info[4]
else:
price = li_info[0]
name = li_info[1]
commit = li_info[2]
market = li_info[3]
print([price, commit, market, name]) def main(self):
self.get_page()
while True:
self.parse_page()
# 判断是否该点击下一页,没有找到说明不是最后一页
if self.browser.page_source.find('pn-next disabled') == -1:
self.browser. \
find_element_by_class_name('pn-next').click()
time.sleep(2)
else:
break if __name__ == '__main__':
spider = JdSpirder("爬虫书籍")
spider.main()
实例解析 - 小米应用下载页面爬虫
页面分析
爬取小米应用商店指定分类下的app 名字和连接
预被爬取的数据是 ajax 请求, F12 抓包选择 XHR 即可看到
配合 并发编程 ( 多线 / 进程 )
* 队列(from multiprocessing import Queue)
q = Queue()
q.put(url)
q.get() :参数block=False,空时抛异常
q.get(block=True,timeout=2) * 线程模块(threading)
from threading import Thread
t = Thread(target=函数名)
t.start()
t.join()
准备工作
URL 地址 'http://app.mi.com/categotyAllListApi?page=%s&categoryId=2&pageSize=30' %str(数字)
爬虫代码
多线程版本
import requests
from threading import Thread
from multiprocessing import Queue
import json
import time class XiaomiSpider(object):
def __init__(self):
self.url_queue = Queue()
self.headers = {'User-Agent': 'Mozilla/5.0'} # URL入队列
def url_in(self):
# 拼接多个URL地址,然后put()到队列中
for i in range(67):
url = 'http://app.mi.com/' \
'categotyAllListApi?' \
'page=%s' \
'&categoryId=2' \
'&pageSize=30' % str(i)
self.url_queue.put(url) # 线程事件函数(请求,解析提取数据)
def get_page(self):
# 先get()URL地址,发请求
# json模块做解析
while True:
# 当队列不为空时,获取url地址
if not self.url_queue.empty():
url = self.url_queue.get()
res = requests.get(url, headers=self.headers)
res.encoding = 'utf-8'
html = res.text
self.parse_page(html)
else:
break # 解析函数
def parse_page(self, html):
html = json.loads(html)
for h in html['data']:
# 应用名称
name = h['displayName']
# 应用链接
link = 'http://app.mi.com/details?id={}' \
.format(h['packageName'])
d = {
'名称': name,
'链接': link
}
with open('小米.json', 'a') as f:
f.write(str(d) + '\n') # 主函数
def main(self):
self.url_in()
# 存放所有线程的列表
t_list = [] for i in range(10):
t = Thread(target=self.get_page)
t.start()
t_list.append(t) # 统一回收线程
for p in t_list:
p.join() if __name__ == '__main__':
start = time.time()
spider = XiaomiSpider()
spider.main()
end = time.time()
print('执行时间:%.2f' % (end - start))
多进程版本
进程需要考虑到多个进程在写一个文件的问题
稍微不太稳定, 所以最好上锁
import requests
from multiprocessing import Process, Lock
from multiprocessing import Queue
import json
import time class XiaomiSpider(object):
def __init__(self):
self.url_queue = Queue()
self.headers = {'User-Agent': 'Mozilla/5.0'}
# 创建锁,操作文件时加锁
self.lock = Lock() # URL入队列
def url_in(self):
# 拼接多个URL地址,然后put()到队列中
for i in range(67):
url = 'http://app.mi.com/' \
'categotyAllListApi?' \
'page=%s' \
'&categoryId=2' \
'&pageSize=30' % str(i)
self.url_queue.put(url) # 线程事件函数(请求,解析提取数据)
def get_page(self):
# 先get()URL地址,发请求
# json模块做解析
while True:
# 当队列不为空时,获取url地址
if not self.url_queue.empty():
url = self.url_queue.get()
res = requests.get(url, headers=self.headers)
res.encoding = 'utf-8'
html = res.text
self.parse_page(html)
else:
break # 解析函数
def parse_page(self, html):
html = json.loads(html)
for h in html['data']:
# 应用名称
name = h['displayName']
# 应用链接
link = 'http://app.mi.com/details?id={}' \
.format(h['packageName'])
d = {
'名称': name,
'链接': link
}
# 加锁
self.lock.acquire()
with open('小米.json', 'a') as f:
f.write(str(d) + '\n')
# 释放锁
self.lock.release() # 主函数
def main(self):
self.url_in()
# 存放所有进程的列表
t_list = [] for i in range(4):
t = Process(target=self.get_page)
t.start()
t_list.append(t) # 统一回收进程
for p in t_list:
p.join() if __name__ == '__main__':
start = time.time()
spider = XiaomiSpider()
spider.main()
end = time.time()
print('执行时间:%.2f' % (end - start))
特殊操作 - 集成 selenium 到Scrapy中
中间件 - selenium 操作
在中间件中执行创建以及爬取相关的操作
但是默认的中间件结束后会交给下载器进行再次爬取
所以这里直接返回 HtmlResponse 返回 response 来绕过
class JSPageMiddleware(object): # 通过chrome请求动态网页
def process_request(self, request, spider):
if spider.name == "jobbole":
# browser = webdriver.Chrome(executable_path="D:/Temp/chromedriver.exe")
spider.browser.get(request.url)
import time
time.sleep(3)
print("访问:{0}".format(request.url)) return HtmlResponse(url=spider.browser.current_url, body=spider.browser.page_source, encoding="utf-8",
request=request)
爬虫类 - 写 初始化 / 释放 函数
因为涉及到 selenium 的创建, 以及释放
如果在中间件中执行就会导致每次的访问都进行操作频繁的释放资源
因此在 爬虫文件中使用更加理想
配合信号量在爬虫爬取结束后自动释放关闭
from selenium import webdriver
from scrapy.xlib.pydispatch import dispatcher
from scrapy import signals
class JobboleSpider(scrapy.Spider):
name = "jobbole"
allowed_domains = ["blog.jobbole.com"]
start_urls = ['http://blog.jobbole.com/all-posts/'] def __init__(self):
self.browser = webdriver.Chrome(executable_path="D:/Temp/chromedriver.exe")
super(JobboleSpider, self).__init__()
dispatcher.connect(self.spider_closed, signals.spider_closed) def spider_closed(self, spider):
#当爬虫退出的时候关闭chrome
print ("spider closed")
self.browser.quit()
---------------------
作者:羊驼之歌
来源:CNBLOGS
原文:https://www.cnblogs.com/shijieli/p/10826743.html
版权声明:本文为作者原创文章,转载请附上博文链接!
内容解析By:CSDN,CNBLOG博客文章一键转载插件
[转]爬虫 selenium + phantomjs / chrome的更多相关文章
- 爬虫 selenium + phantomjs / chrome
selenium 模块 Web自动化测试工具, 可运行在浏览器,根据指定命令操作浏览器, 必须与第三方浏览器结合使用 安装 sudo pip3 install selenium phantomjs 浏 ...
- [Python爬虫] Selenium+Phantomjs动态获取CSDN下载资源信息和评论
前面几篇文章介绍了Selenium.PhantomJS的基础知识及安装过程,这篇文章是一篇应用.通过Selenium调用Phantomjs获取CSDN下载资源的信息,最重要的是动态获取资源的评论,它是 ...
- [Python爬虫] Selenium +phantomjs 模拟下拉滚动条
在爬虫中,有时会遇到这种情况,数据的展示是不是一页一页的,而是通过不断的下拉滚动条来加载数据.例如一点咨询(http://www.yidianzixun.com/)和微博(在未登录的状态下:http: ...
- [python爬虫] Selenium常见元素定位方法和操作的学习介绍
这篇文章主要Selenium+Python自动测试或爬虫中的常见定位方法.鼠标操作.键盘操作介绍,希望该篇基础性文章对你有所帮助,如果有错误或不足之处,请海涵~同时CSDN总是屏蔽这篇文章,再加上最近 ...
- Selenium + PhantomJS + python 简单实现爬虫的功能
Selenium 一.简介 selenium是一个用于Web应用自动化程序测试的工具,测试直接运行在浏览器中,就像真正的用户在操作一样 selenium2支持通过驱动真实浏览器(FirfoxDrive ...
- selenium + firefox/chrome/phantomjs登陆之模拟点击
登陆之模拟点击 工具:python/java + selenium + firefox/chrome/phantomjs (1)windows开发环境搭建 默认已经安装好了firefox 安装pip ...
- 学习用java基于webMagic+selenium+phantomjs实现爬虫Demo爬取淘宝搜索页面
由于业务需要,老大要我研究一下爬虫. 团队的技术栈以java为主,并且我的主语言是Java,研究时间不到一周.基于以上原因固放弃python,选择java为语言来进行开发.等之后有时间再尝试pytho ...
- selenium设置chrome和phantomjs的请求头信息
selenium设置chrome和phantomjs的请求头信息 出于反爬虫也好-跳转到手机端页面也好都需要设置请求头,那么如何进行呢? 目录 一:selenium设置phantomjs请求头: ...
- 爬虫之 图片懒加载, selenium , phantomJs, 谷歌无头浏览器
一.图片懒加载 懒加载 : JS 代码 是页面自然滚动 window.scrollTo(0,document.body.scrollHeight) (重点) bro.execute_ ...
随机推荐
- 替换文本:将文本文件中的所有src替换为dst
题意: 将文本文件中的所有src替换为dst 方法一:使用String import java.io.File; import java.io.FileNotFoundException; impor ...
- vue+axios 对restful 请求封装
礼拜天来公司整理项目,项目是最近开始重构的,里面的各种http请求接口是restful结构的(为了提升项目的比格),整理一下笔记 [restful介绍][1]博主讲的很详细 技术栈: vue + vu ...
- oracle误操作commit之后,可以闪回数据
1. 授予行迁移权限 alter table table_name enable row movement; 2. 到15分钟前: flashback table order to timesta ...
- day38 12-Spring的Bean的属性的注入:名称空间p
xmlns="http://www.springframework.org/schema/beans"是默认的名称空间. xmlns:xsi="http://www.w3 ...
- Leetcode917.Reverse Only Letters仅仅反转字母
给定一个字符串 S,返回 "反转后的" 字符串,其中不是字母的字符都保留在原地,而所有字母的位置发生反转. 示例 1: 输入:"ab-cd" 输出:" ...
- 随机模块(import random)
随机的概念: 在某个范围内取到的每一个值的概率是相同的 随机小数: 1.random.random() #0-1之内的随机小数 2.random.unifom(1,5) #范围之内的随机小数 随机整数 ...
- JQuery--关系选择器
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 自学FPGA笔记之 “有限状态机”
“有限状态机”,一份好的代码必需掌握的技能. 首先状态机需要分清楚一共有多少种状态,其次画出状态图,状态图根据需求来画,尽可能的细分画到每一个状态,如有需要用到状态机一定要画出状态图,一定要画出状态图 ...
- Java中的四种引用(强引用、软引用、弱引用、虚引用)
以下内容摘自<深入理解Java虚拟机 JVM高级特性与最佳实践>第2版,强烈推荐没有看过的同学阅读,读完的感觉就是"原来学的都是些什么瘠薄东西(╯‵□′)╯︵┴─┴" ...
- win2003开启ftp
首先你要添加IIS,然后才可以启动配置FTP,步骤如下: 1.控制面板→添加或删除程序→添加/删除windows组件: 2.在弹出的windows组件向导窗口中,选择并勾选“应用程序服务器”,然后点击 ...