前面总结了通过寻找后台接口来爬取动态网页,这篇博客总结一下selenium+chrome如何爬取动态页面,selenium现在貌似不在支持PhantomJs,python版本为3.6
1、安装chromedriver
网址:http://chromedriver.chromium.org/downloads(需要翻墙)
请安装与自己chrome版本(在浏览器地址栏输入chrome://settings/help可查看)一致的chromedriver
下载完后,将chromedriver的所有文件拖到chrome的安装文件夹,设置到chrome安装文件夹的环境变量(方便代码处理)
2、查看selenium官方文档
网址:http://selenium-python.readthedocs.io/api.html#module-selenium.webdriver.chrome.webdriver
常用函数总结一下:
#selenium.webdriver.chrome.webdriver.WebDriver类
__init__:第一个形参用于指定chromedriver的路径,如果不指定,使用
环境变量path下的路径,第二个参数指定运行端口号,如果不指定,随便选择一个空端口号
quite():关闭浏览器
#selenium.webdriver.chrome.options.Options
用于设置chrome浏览器,目前使用过的参数:
1、阻止chrome弹窗的出现:'profile.default_content_setting_values' :{'notifications' : 2}
2、不加载图片:"profile.managed_default_content_settings.images":2
3、无头浏览器,--headless
add_experimental_option(name, value):将设置参数传递给chrome
#selenium.webdriver.remote.webdriver.WebDriver
close():关闭当前窗口
execute_async_script():异步执行js代码
execute_script():同步执行js代码
quit():关闭驱动以及所有窗口
get(url):获得某个页面
set_window_size(width, height, windowHandle='current'):设置窗口大小
maximize_window():窗口最大化
page_source属性,获得当前页面的html代码
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);":执行翻页
find_element_by_id:全文查找,根据完整的id值查找,返回selenium.webdriver.remote.webelement.WebElement对象
find_element_by_class_name:全文查找,根据完整的class值查找,返回selenium.webdriver.remote.webelement.WebElement对象
find_element_by_xpath(xpath):全文查找,根据xpath查找,返回selenium.webdriver.remote.webelement.WebElement对象
#selenium.webdriver.remote.webelement.WebElement
click():点击按钮
find_element_by_id:根据id查找,返回selenium.webdriver.remote.webelement.WebElement对象,只查找子元素
find_element_by_class_name:根据class name查找,返回selenium.webdriver.remote.webelement.WebElement对象,只查找子元素
find_element_by_xpath(xpath):根据xpath查找,返回selenium.webdriver.remote.webelement.WebElement对象,只查找子元素
submit():提交表单
send_keys():填值
text属性:该元素的文本值
3、常见异常
NoSuchElementException
关于起因,我总结了两点:
1、页面元素未被加载出来,这里有两种可能
第一、等待时间过短,导致元素未加载
第二、浏览器窗口不够大,导致页面元素未加载,此时不论等待多长时间都没用,因此,每次都要将窗口设置为最大值
2、寻找元素的标记本身发生错误
4、实例
爬取迪丽热巴的微博发言,由于是练习,因此会有一些不必要的步骤
引入的包:
from selenium import webdriver
import time
from lxml import etree
1、实例化webdriver
options = webdriver.ChromeOptions()
prefs = {
'profile.default_content_setting_values' :
{
'notifications' : 2
},
"profile.managed_default_content_settings.images":2
}
options.add_experimental_option('prefs',prefs)
driver = webdriver.Chrome(chrome_options = options)
driver.maximize_window()
禁止chrome弹窗(注意是chrome自带的弹窗,不是网站的弹窗)、不加载图片
2、登陆微博
注意到弹窗的存在,如果不设置,chrome就会有弹窗,但是不妨碍处理网页
登陆用户具有更多的浏览权限,因此需要登陆
def login_weibo():
driver.get('https://weibo.com/')
time.sleep(10)
element=driver.find_element_by_id('loginname')
element.send_keys('你的账号名')
element=driver.find_element_by_name('password')
element.send_keys('你的密码')
element=driver.find_element_by_class_name('W_btn_a')
element.click()
这里有一个坑,如果不最大化窗口,微博首页的登陆框是不会出现的(google、百度了一堆,没啥用,然后才发现这么回事.....
这个登陆方式不是很完善,没有验证码的处理,但验证码并不常见(尝试登陆了几十次,没见过验证码.......),所以就不写了,出现验证码可以尝试用OCR的识别手段,也可以考虑自己手工输入
3、在搜索框搜索迪丽热巴并点击
def search_weibo():
#查找搜索框并输入信息
elements=driver.find_elements_by_class_name('W_input')
elements[0].send_keys('迪丽热巴')
#点击搜索按钮
element=driver.find_element_by_class_name('ficon_search')
element.click()
time.sleep(10)
#进入迪丽热巴的微博
element=driver.find_element_by_class_name('name_txt')
element.click()
time.sleep(10)
这里设置了等待时间,因为整个页面的加载速度奇慢,如果等待时间不足,可能相应的元素就无法加载
4、选在查看全部微博
这个权限在登陆后才有
def select_all():
#定位最新打开的窗口
windows = driver.window_handles
driver.switch_to.window(windows[-1])
#选择全部按钮,点击
element=driver.find_element_by_xpath("//li[@class='tab_li tab_li_first']/a")
element.click()
time.sleep(10)
这里有个坑,如果我们用selenium让chrome打开了多个窗口,chrome的webdriver不会定位到最新的窗口,而是一直处于第一个窗口,所以前两行代码用于定位最新打开的窗口
5、爬取前三页微博信息
def crawel():
i=0
while(i!=3):
#翻页
driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
time.sleep(5)
#使用etree查看是否有下一页元素
page=driver.page_source
html_parse=etree.HTML(page)
a=html_parse.xpath("//a[@class='page next S_txt1 S_line1']")
#存在下一页元素,此时该页全部加载完毕,爬取
if a!=[]:
text_list=html_parse.xpath("//div[@class='WB_text W_f14']")
for index in range(0,len(text_list)):
result=text_list[index].text.replace(' ','').replace('\n','')
if result!='':
file.write(result+'\n')
element=driver.find_element_by_class_name('next')
element.click()
i=i+1
微博需要下拉一定长度才会出现下一页的标签,在网上查找了许多下拉网页的方式都没用,最后查阅官方文档才找到答案:
driver.execute_script("window.scrollTo(0, document.body.scrollHeight)")
lxml元素选择器的处理速度比selenium快很多,查找不到也不会抛异常,因此,寻找下一页元素我选择使用lxml(网页要下拉到最底才会出现下一页标识符,未出现下一页标识符,selenium会抛异常),这里没有处理因网络原因导致的重新加载情况
6、部分执行结果(CSDN不知咋回事,只能丢出这么点文本)
果然,最喜欢夏天
自从这个妹妹出道以后老学我
希望平安无事