前面爬取的网页均为静态网页,这样的网页在浏览器中展示的内容都位于HTML源代码中。但是由于主流网站使用JavaScript展现网页内容,和静态网页不同的是,使用JavaScript时,很多内容并不会出现在HTML源代码中,所以爬取静态网页的技术可能无法正常使用。因此,我们需要用到动态网页抓取的两种技术:通过浏览器审查元素解析真实网页地址和使用Selenium模拟浏览器的方法。
1 动态抓取的实例
因此,我们如果使用 AJAX 加载的动态网页,怎么爬取里面动态加载的内容呢?有两种方法:
- 通过浏览器审查元素解析地址
- 通过selenium模拟浏览器抓取
2 动态抓取的实例
方法1操作步骤:
- 打开浏览器“检查”功能。
- 找到真实的数据地址。点击对话框中的Network,然后刷新网页。此时,Network 会显示浏览器从网页服务器中得到的所有文件,一般这个过程称之为“抓包”。
- 爬取真实评论数据地址。既然找到了真实的地址,我们就可以直接用requests请求这个地址,获取数据。
- 从 json数据中提取评论。上述的结果比较杂乱,但是它其实是 json 数据,我们可以使用 json 库解析数据,从中提取我们想要的数据
import requests
import json
def single_page_comment(link):
headers = {'User-Agent' : 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-US; rv:1.9.1.6) Gecko/20091201 Firefox/3.5.6'}
r = requests.get(link, headers= headers)
# 获取 json 的 string
json_string = r.text
json_string = json_string[json_string.find('{'):-2]
json_data = json.loads(json_string)
comment_list = json_data['results']['parents']
for eachone in comment_list:
message = eachone['content']
print (message)
for page in range(1,4):
link1 = "https://api-zero.livere.com/v1/comments/list?callback=jQuery112403473268296510956_1531502963311&limit=10&offset="
link2 = "&repSeq=4272904&requestPath=%2Fv1%2Fcomments%2Flist&consumerSeq=1020&livereSeq=28583&smartloginSeq=5154&_=1531502963316"
page_str = str(page)
link = link1 + page_str + link2
print (link)
single_page_comment(link)
3 通过selenium 模拟浏览器抓取
我们可以用Python的selenium库模拟浏览器完成抓取。Selenium是一个>用于Web应用程序测试的工具。Selenium测试直接运行在浏览器中,浏>览器自动按照脚本代码做出点击,输入,打开,验证等操作,就像真正的用户在操作一样。
步骤:
- 找到评论的HTML代码标签。使用Chrome打开该文章页面,右键点击页面,打开“检查”选项。按照第二章的方法,定位到评论数据。
- 尝试获取一条评论数据。在原来打开页面的代码数据上,我们可以使用以下代码,获取第一条评论数据。在下面代码中,driver.find_element_by_css_selector是用CSS选择器查找元素,找到class为’reply-content’的div元素;find_element_by_tag_name则是通过元素的tag去寻找,意思是找到comment中的p元素。最后,再输出p元素中的text文本。
- 我们可以在 jupyter 中键入driver.page_source
找到为什么没有定位到评论元素,通过排查我们发现,原来代码中的 JavaScript 解析成了一个 iframe,<iframe title=”livere” scrolling=”no”…>也就是说,所有的评论都装在这个框架之中,里面的评论并没有解析出来,所以我们才找不到div.reply-content元素。这时,我们需要加上对 iframe 的解析。
from selenium import webdriver
import time
driver = webdriver.Firefox(executable_path = r'C:\Users\santostang\Desktop\geckodriver.exe')
driver.implicitly_wait(20) # 隐性等待,最长等20秒
#把上述地址改成你电脑中geckodriver.exe程序的地址
driver.get("http://www.santostang.com/2018/07/04/hello-world/")
time.sleep(5)
for i in range(0,3):
# 下滑到页面底部
driver.execute_script("window.scrollTo(0, document.body.scrollHeight);")
# 转换iframe,再找到查看更多,点击
driver.switch_to.frame(driver.find_element_by_css_selector("iframe[title='livere']"))
load_more = driver.find_element_by_css_selector('button.more-btn')
load_more.click()
# 把iframe又转回去
driver.switch_to.default_content()
time.sleep(2)
driver.switch_to.frame(driver.find_element_by_css_selector("iframe[title='livere']"))
comments = driver.find_elements_by_css_selector('div.reply-content')
for eachcomment in comments:
content = eachcomment.find_element_by_tag_name('p')
print (content.text)
selenium选择元素的方法有很多:
- find_element_by_id:通过元素的id选择,例如:driver.find_element_by_id(‘loginForm’)
- find_element_by_name:通过元素的name选择,driver.find_element_by_name('password')
- find_element_by_xpath:通过xpath选择,driver.find_element_by_xpath(“//form[1]”)
- find_element_by_link_text:通过链接地址选择
- find_element_by_partial_link_text:通过链接的部分地址选择
- find_element_by_tag_name:通过元素的名称选择
- find_element_by_class_name:通过元素的id选择
- find_element_by_css_selector:通过css选择器选择
有时候,我们需要查找多个元素。在上述例子中,我们就查找了所有的评论。因此,也有对应的元素选择方法,就是在上述的element后加上s,变成elements。
其中xpath和css_selector是比较好的方法,一方面比较清晰,另一方面相对其他方法定位元素比较准确。
除此之外,我们还可以使用selenium操作元素方法实现自动操作网页。常见的操作元素方法如下:
– clear 清除元素的内容
– send_keys 模拟按键输入
– click 点击元素
– submit 提交表单
user = driver.find_element_by_name("username") #找到用户名输入框
user.clear #清除用户名输入框内容
user.send_keys("1234567") #在框中输入用户名
pwd = driver.find_element_by_name("password") #找到密码输入框
pwd.clear #清除密码输入框内容
pwd.send_keys("******") #在框中输入密码
driver.find_element_by_id("loginBtn").click() #点击登录
由于篇幅有限,有兴趣的读者,可以到selenium的官方文档查看:http://selenium-python.readthedocs.io/index.html