运用selenium爬取知乎timeline动态加载内容
在前之前文章中尝试用简单的Requests爬取知乎timeline时发现动态加载内容无法成功爬取,尝试分析数据包来爬取也没有成功,于是最后在这里使用selenium来尝试,终于成功。
全部代码见于我的Git
selenium思路
网上关于selenium的教程有很多,也很详细,但还是推荐看官方文档,单就爬虫而言,看完官方文档的example够用了。
使用selenium的思路就是利用selenium对浏览器的操作,模拟人下拉页面,从而让网站实现动态加载。
首先要使用selenium必须安装对应浏览器的webdriver,官方文档1.3节中有相应说明,由于一些原因,在这里使用的是Microsoft edge浏览器,edge的webdriver与其他几家不同,下载下来是个exe文件,需要放到path中存在的文件夹中才能顺利杯selenium调用,我选择的是放在python文件夹中。
对于模拟人下拉页面,主要思路是,获取滚动条的高度,然后让滚动条的深度=高度,于是滚动条到底了,触发页面动态加载。
def down_page(driver, times):
for i in range(0, times+1):
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
time.sleep(1)
实际上是在selenium中使用的javascript来对浏览器进行操作。
driver是通过webdriver.Edge()创建的drivers对象
times是向下滑动的次数
execute_script()是使用javascript脚本进行
使用方法如下:
def main():
url = 'https://www.zhihu.com'
driver = webdriver.Edge()
driver.get(url)
down_page(driver, 10)
html = driver.page_source
几个要点
虽然参考了许多资料,但是还是遇到了许多问题,这里进行一下记录与说明。
注意cookies
selenium对cookies的保存方式与requests不同:
requests是直接以字典形式存储:
{'name':'value','name':'value'}
selenium则是以字典列表存储,其中每个字典存储一对name:value,形式为
[
{'name':'namedata', 'value':'valuetat', 'path':'pathdata', 'domain':'domaindata', 'expiry': number, 'secure': False/Truse, 'httpOnly': False/Truse},
{'name':'namedata', 'value':'valuetat', 'path':'pathdata', 'domain':'domaindata', 'expiry': number, 'secure': False/Truse, 'httpOnly': False/Truse},
]
所以,若想用driver.add_cookies()加入cookies需要先通过driver.get_cookies()获得path、domain等内容再去构建cookies。
在这里,因为edge的webdriver本身保留之前的cookies记录,所以只要之前在爬取前登录一次网页即可。
(网上有说selenium打开的窗口是全新的无cookies,可能在Firefox或者Chrome上存在,Edge不存在这个困扰)
获取网页代码
对网页代码的获取使用的是
html = driver.page_source
这个方法和requesrs.get()所获取的页面代码是有区别的(更详细)所以正则表达式得重写。
自动登录
尝试过进行自动登录,碰到了三个问题:
1.网上可查到的删除cookies的方法delete_all_cookies()和delete_cookie()是错误的,准确的说不是错的,而是这个方法在selenium中是用在Remote WebDriver中的,本地使用并没有删除cookie的方法。
猜想:都在本地了,自己在程序运行之前手动删一下,不就成了?
2.如果浏览器已经 保存密码 了,那么以下代码会出现问题:
account = driver.find_element_by_name('account')
password = driver.find_element_by_name('password')
account.clear()
password.clear()
time.sleep(1)
account.send_keys('account') #换成自己账号
password.send_keys('password') #换成自己密码
问题在于 即使你清除了文本内容,只要你send_keys,浏览器就会自动填充密码,于是你再填充一次密码,在密码栏中就填了两遍密码,明显会密码错误。
删除浏览器记录的密码,或者干脆去掉password.send_keys语句
3.知乎的倒立汉字验证码真的很烦。。。。
怎么解决这个问题,查了一些资料,还在研究,但是并不影响本次程序的正常运行,所以留待下篇文章再说
自动登录代码(无验证码、无自动填充密码):
from selenium import webdriver
import time
def login(driver):
time.sleep(2)
driver.find_element_by_link_text('登录').click()
time.sleep(1)
driver.find_element_by_class_name('signin-switch-password').click()
time.sleep(1)
account = driver.find_element_by_name('account')
password = driver.find_element_by_name('password')
account.clear()
password.clear()
time.sleep(1)
account.send_keys('account') #换成自己账号
password.send_keys('password') #换成自己密码
time.sleep(5)
driver.find_element_by_class_name('sign-button submit').click()
def main():
url = "http://www.zhihu.com"
driver = webdriver.Edge()
driver.get(url)
try:
driver.find_element_by_link_text('登录')
except Exception as e:
print('已经登录')
else:
login(driver)
cookie = driver.get_cookies()
print(cookie)
if __name__ == '__main__':
main()
这里,因为selenium中get element语句只要没有获得结果就会报错,所以不能用if判断,必须用try语句。