selenium2 + 无界面浏览器 + pyquery 是个人认为功能最强大的爬虫组合(这一套本来是用做自动化测试的),有人问为啥不是bs4而是pyquery,因为我对jquery很熟悉,而且我不喜欢bs4的查询语法.所以我选择了pyquery来降低学习成本.仅此而已.这中间的无界面浏览器,最常见的是PhantomJS,但是selenium说人家phantomjs不思进取,声明将来不给它玩了(运行时会抛出"Selenium support for PhantomJS has been deprecated, please use headless versions of Chrome or Firefox instead"的警告),所以建议还是用headless版本的chrome或者firefox来替代.接下来让我们开始吧.
安装
安装selenium2
pip3 install selenium
或者
pip install selenium
视你的python版本和环境而定.
如果你要安装phantomjs.
sudo apt-get install phantomjs
安装 pyquery
pip3 install pyquery
服务器端,我们建议headless版本的浏览器,比如chrome.
安装Xvfb 一个仿真的视窗框架,可以让没有显示硬件的设备虚拟一个显示设备.
sudo apt-get install xvfb
安装PyVirtualDisplay,这是一个Xvfb的包装器.
pip3 install pyvirtualdisplay
安装chrome
第一步,加入源列表
sudo wget http://www.linuxidc.com/files/repo/google-chrome.list -P /etc/apt/sources.list.d/
第二步 导入公钥
wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | sudo apt-key add -
第三步 更新源列表
sudo apt-get update
第四步 安装chrome
sudo apt-get install google-chrome-stable
安装完成下载chromedriver也就是headless版本的chrome.https://chromedriver.storage.googleapis.com/index.html?path=2.35/
你也可以自行搜索chromedriver的下载地址,解压是个可执行文件,放到chrome的目录即可.
一般ubuntu下面,chrome的目录是/opt/google/chrome/
通过以上准备基本都齐了,我们来上一段代码:
接下来是一个简单的操作,打开一个页面,输入密码,执行一段脚本,输入一些数据,然后提交
# -*- coding: utf-8 -*-
from selenium import webdriver
from pyvirtualdisplay import Display
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as ec
from selenium.webdriver.support.select import By
import datetime
import time
import os
"""演示"""
display = Display(visible=0, size=(1024, 768))
# display.start() # 开启虚拟显示器
"""
https://chromedriver.storage.googleapis.com/index.html?path=2.35/
你也可以自行搜索chromedriver的下载地址,解压是个可执行文件,放到chrome的目录即可.
一般ubuntu下面,chrome的目录是/opt/google/chrome/
"""
chrome_driver = "/opt/google/chrome/chromedriver" # chromedriver的路径
os.environ["ChromeDriver"] = chrome_driver # 必须配置,否则会在execute_script的时候报错.
browser = webdriver.Chrome(chrome_driver)
wait = WebDriverWait(browser, 10)
url_1 = "https://some_url"
browser.get(url=url_1) # 打开页面
# 密码输入按钮
input_password = wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, ".x-layout-table input[type='password']")))
# 提交按钮
submit_password = wait.until(ec.element_to_be_clickable((By.CSS_SELECTOR, ".x-layout-table .x-btn span")))
input_password.send_keys("password") # 输入密码
time.sleep(1)
submit_password.click() # 提交密码
time.sleep(3) # 等待是为了给页面时间载入
# 修改时间选择器输入框脚本
js_datepicker = """let d = $(".widget-wrapper>ul>li:first input"); d.val("{}");""".\
format(datetime.datetime.now().strftime("%F"))
browser.execute_script(js_datepicker) # 输入时间
js_name = """let d = $(".widget-wrapper>ul>li:eq(1) input"); d.val("{}");""".format("测试人员")
browser.execute_script(js_name) # 输入姓名
js_phone = """let d = $(".widget-wrapper>ul>li:eq(2) input"); d.val("{}");""".format("18888888888")
browser.execute_script(js_phone) # 输入电话
js_desc_1 = """let d = $(".widget-wrapper>ul>li:eq(3) input"); d.val("{}");""".format("测试信息.")
browser.execute_script(js_desc_1) # 备注1
"""selenium.common.exceptions.WebDriverException: Message: unknown error: cannot focus element"""
"""ec.presence_of_all_elements_located方法可以取一组输入框,然后循环操作"""
input_list = wait.until(ec.presence_of_all_elements_located((By.CSS_SELECTOR, ".widget-wrapper>ul>li input"))) #输入组
submit_info = wait.until(ec.presence_of_element_located((By.CSS_SELECTOR, ".x-btn span"))) # 提交资料按钮
submit_info.click() # 提交信息
time.sleep(1)
browser.refresh() # 刷新页面
time.sleep(10)
browser.quit()
# display.stop() # 关闭虚拟显示器
有关pyquery的内容这里略过了,熟悉jquery的童鞋凭感觉操作就行了.0学习成本.
补充:
1. 有关PyVirtualDisplay的部分
其实PyVirtualDisplay可以不装.使用headless配置项即可.我这里写了一个方法,注释里面有一些说明,和大家分享一下.
from selenium.webdriver.support.ui import WebDriverWait
from selenium.common.exceptions import TimeoutException
from selenium.webdriver import FirefoxProfile
from selenium.webdriver import FirefoxOptions
from selenium.webdriver import Firefox
from selenium.webdriver import ChromeOptions
from selenium.webdriver import Chrome
def get_browser(headless: bool = True, browser_class: int = 1) -> Firefox:
"""
获取一个浏览器
:param headless:
:param browser_class: 浏览器种类,0是谷歌, 1 是火狐,
:return:
"""
"""
firefox的headless浏览器
因为headless的浏览器的语言跟随操作系统,为了保证爬回来的数据是正确的语言,
这里必须设置浏览器的初始化参数,
注意,使用headless必须先安装对应浏览器正常的版本,然后再安装headless版本
比如火狐的headless
下载火狐的geckodriver驱动。(当前文件夹下已经有一个了)地址是:
https://github.com/mozilla/geckodriver/releases
下载后解压是一个geckodriver 文件。拷贝到/usr/local/bin目录下,然后加上可执行的权限
sudo chmod +x /usr/local/bin/geckodriver
chrome的headless浏览器
https://chromedriver.storage.googleapis.com/index.html?path=2.35/
你也可以自行搜索chromedriver的下载地址,解压是个可执行文件,放到chrome的目录即可.
一般ubuntu下面,chrome的目录是/opt/google/chrome/
据说使用root权限运行的话,chrome的headless浏览器会报异常.而firefox的headless浏览器不会!
"""
if browser_class == 1:
profile = FirefoxProfile()
profile.set_preference("intl.accept_languages", "zh-cn")
options = FirefoxOptions()
options.add_argument("--headless")
if headless:
try:
browser = Firefox(firefox_profile=profile, firefox_options=options)
except Exception as e:
title = "{} Firefox headless浏览器打开失败".format(datetime.datetime.now())
content = "错误原因是:{}".format(e)
send_mail(title=title, content=content)
recode(e)
logger.exception(e)
raise e
else:
try:
browser = Firefox(firefox_profile=profile)
except Exception as e:
title = "{} Firefox headless浏览器打开失败".format(datetime.datetime.now())
content = "错误原因是:{}".format(e)
send_mail(title=title, content=content)
recode(e)
logger.exception(e)
raise e
else:
options = ChromeOptions()
options.add_argument("--headless")
if headless:
try:
browser = Chrome(executable_path=chrome_driver, chrome_options=options)
except Exception as e:
title = "{} Chrome headless浏览器打开失败".format(datetime.datetime.now())
content = "错误原因是:{}".format(e)
send_mail(title=title, content=content)
recode(e)
logger.exception(e)
raise e
else:
try:
browser = Chrome(executable_path=chrome_driver)
except Exception as e:
title = "{} Chrome headless浏览器打开失败".format(datetime.datetime.now())
content = "错误原因是:{}".format(e)
send_mail(title=title, content=content) # 这是我自定义的方法
recode(e)
logger.exception(e)
raise e
return browser