赞
踩
上一部分了解了Ajax的分析和抓取方式,但有些网页比如淘宝,其Ajax接口含有很多加密参数,我们难以直接找出其规律,也很难直接分析Ajax来抓取。
为了解决这些问题,我们可以直接使用 模拟浏览器运行 的方式来实现,这样就可以做到在浏览器中看到的是什么样,抓取的源码就是什么样,也就是可见即可爬。这样就不用管网页内部的JS用了什么算法去渲染、加载页面,也不用管网页后台的Ajax接口到底有哪些参数。
懒得截图了(每次截图都弄不好TAT)
它是一个强大的库,首先你需要去安装它pip install selenium
。它可以用几行代码,控制浏览器,做出自动打开、输入、点击等操作,就像是有一个真正的用户在操作一样。
而对于那些交互复杂、加密复杂的网站,selenium
问题简化,爬动态网页如爬静态网页一样简单。
而关于动态网页和静态网页,其实你都已经接触过了。
前边第Ⅰ部分用html
写出的网页,就是静态网页。我们使用BeautifulSoup
爬取这类型网页,因为网页源代码中就包含着网页的所有信息(第0个请求里,在preview
里就能看到所有信息),因此,网页地址栏的URL
就是网页源代码的URL
。
后来在第Ⅱ部分,开始接触更复杂的网页,比如QQ音乐,要爬取的数据不在HTML源代码中,而是在json
中,你就不能直接使用网址栏的URL
了,而需要找到json
数据的真实URL
。这就是一种动态网页。
不论数据存在哪里,浏览器总是在向服务器发起各式各样的请求,当这些请求完成后,它们会一起组成开发者工具的Elements
中所展示的,渲染完成的网页源代码。
在遇到页面交互复杂或是URL
加密逻辑复杂的情况时,selenium
就派上了用场,它可以真实地打开一个浏览器,等待所有数据都加载到Elements
中之后,再把这个网页当做静态网页爬取就好了。
说了这么多优点,使用selenium
时,当然也有美中不足之处。
由于要真实地运行本地浏览器,打开浏览器以及等待网渲染完成需要一些时间,selenium
的工作不可避免地牺牲了速度和更多资源,不过,至少不会比人慢。
首先呢你需要下载好Chrome浏览器
,然后去http://npm.taobao.org/mirrors/chromedriver/2.44/这里,下载好浏览器驱动,再放到 python的安装目录下。然后本地运行一下下边的代码,有浏览器弹出来打开的是百度首页并搜索了“Python”,下拉到最底部,最后弹出了一个提示,那就安装成功了(/≧▽≦)/
# -*- coding:utf-8 -*- from selenium import webdriver from selenium.webdriver.common.keys import Keys import time driver = webdriver.Chrome() driver.get('http://www.baidu.com') Search = driver.find_element_by_id('kw') Search.send_keys('Python') time.sleep(1) Search.send_keys(Keys.ENTER) time.sleep(2) driver.execute_script('window.scrollTo(0, document.body.scrollHeight)') time.sleep(2) driver.execute_script('alert("To Bottom")') time.sleep(2) driver.close()
# 本地Chrome浏览器设置方法
from selenium import webdriver #从selenium库中调用webdriver模块
driver = webdriver.Chrome()
# 设置引擎为Chrome,真实地打开一个Chrome浏览器(然后赋值给变量driver,它就是一个实例化的浏览器)
我们前面使用BeautifulSoup
解析网页源代码,然后提取其中的数据。selenium
库同样也具备解析数据、提取数据的能力。它和BeautifulSoup
的底层原理一致,但在一些细节和语法上有所出入。selenium
所解析提取的,是Elements
中的所有数据,而BeautifulSoup
所解析的则只是Network
中第0个请求的响应。而用selenium
把网页打开,所有信息就都加载到了Elements
那里,之后,就可以把动态网页用静态网页的方法爬取了(我不是复读机)。
再拿QQ音乐https://y.qq.com/portal/search.html#page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=%E5%91%A8%E6%9D%B0%E4%BC%A6来做例子,看注释:
from selenium import webdriver
import time
driver = webdriver.Chrome() #设置浏览器
url = 'https://y.qq.com/portal/search.html#page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=%E5%91%A8%E6%9D%B0%E4%BC%A6'
driver.get(url)#get(URL)是webdriver的一个方法,它的使命是为你打开指定URL的网页。
time.sleep(2)#由于浏览器缓冲加载网页需要耗费一些时间,等待1-2秒再去解析和提取比较稳妥。
driver.close()
先回想下,使用BeautifulSoup
从获取的数据中提取数据时,首先要把Response
对象解析为BeautifulSoup
对象,然后再从中提取数据。
而在selenium
中,获取到的网页存在了driver
中,而后,获取和解析是同时做的,都是由driver
这个实例化的浏览器完成。也就是说解析数据是由driver
自动完成的(8用我们管),提取数据是driver
的一个方法:
方法 | 作用 |
---|---|
find_element_by_tag_name | 以上就是提取单个元素的方法了 |
find_element_by_class_name | 见名知意,无需多言! |
find_element_by_id | 而要提取多个元素,只需要把 element 换成 elements 就好啦 |
find_element_by_name | 还要注意不能定位复合类名,如不能find_element_by_class_name(‘xxx xxx’) |
find_element_by_link_text | |
find_element_by_partial_link_text |
提取出的元素是<class 'selenium.webdriver.remote.webelement.WebElement'>
这个类的,它与BeautifulSoup
中的Tag
对象类似,也有提取文本和属性值的属性,下面放WebElement对象与Tag对象的用法对比:
WebElement | Tag | 作用 |
---|---|---|
WebElement.text | Tag.text | 提取文字 |
WebElement.get_attribute() | Tag[ ] | 填入属性名,返回属性值 |
示例一下:
# 以下方法都可以从网页中提取出'你好啊!'这段文字------------------- find_element_by_tag_name:通过元素的名称选择 # 如<h1>你好啊!</h1> # 可以使用find_element_by_tag_name('h1') find_element_by_class_name:通过元素的class属性选择 # 如<h1 class="title">你好啊!</h1> # 可以使用find_element_by_class_name('title') find_element_by_id:通过元素的id选择 # 如<h1 id="title">你好啊!</h1> # 可以使用find_element_by_id('title') find_element_by_name:通过元素的name属性选择 # 如<h1 name="hello">你好啊!</h1> # 可以使用find_element_by_name('hello') #以下两个方法可以提取出超链接------------------------------------ find_element_by_link_text:通过链接文本获取超链接 # 如<a href="spidermen.html">你好啊!</a> # 可以使用find_element_by_link_text('你好啊!') find_element_by_partial_link_text:通过链接的部分文本获取超链接 # 如<a href="https://localprod.pandateacher.com/python-manuscript/hello-spiderman/">你好啊!</a> # 可以使用find_element_by_partial_link_text('你好')
还是QQ音乐周杰伦的歌曲名https://y.qq.com/portal/search.html#page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=%E5%91%A8%E6%9D%B0%E4%BC%A6,这里只提取第一页的,用selenium就不需要去json中找啦~!
# -*- coding: utf-8 -*- from selenium import webdriver import time driver = webdriver.Chrome() #设置浏览器 url = 'https://y.qq.com/portal/search.html#page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=%E5%91%A8%E6%9D%B0%E4%BC%A6' driver.get(url)#get(URL)是webdriver的一个方法,它的使命是为你打开指定URL的网页。 time.sleep(2)#由于浏览器缓冲加载网页需要耗费一些时间,等待1-2秒再去解析和提取比较稳妥。 # 直接定位提取数据 song_ul = driver.find_element_by_class_name('songlist__list') song_li = song_ul.find_elements_by_class_name('js_songlist__child') for song in song_li: name = song.find_element_by_class_name('songlist__songname_txt') print(name.text.strip()) driver.close()
先用selenium获取到渲染完整的网页源代码,再以字符串形式返回给BS拿去解析和提取。(自己想为啥)
如何获取呢?也是使用driver
的一个方法:page_source
HTML源代码字符串 = driver.page_source
示例:
# -*- coding: utf-8 -*- from selenium import webdriver import time,bs4 driver = webdriver.Chrome() #设置浏览器 url = 'https://y.qq.com/portal/search.html#page=1&searchid=1&remoteplace=txt.yqq.top&t=song&w=%E5%91%A8%E6%9D%B0%E4%BC%A6' driver.get(url)#get(URL)是webdriver的一个方法,它的使命是为你打开指定URL的网页。 time.sleep(2)#由于浏览器缓冲加载网页需要耗费一些时间,等待1-2秒再去解析和提取比较稳妥。 # 用BS解析网页 song = bs4.BeautifulSoup(driver.page_source,'html.parser') # 直接定位提取数据 song_ul = song.find(class_='songlist__list') song_li = song_ul.find_all(class_='js_songlist__child') for song in song_li: name = song.find(class_='songlist__songname_txt') print(name.text.strip()) driver.close()
没用selenium之前,我们只用BS解析是爬不到歌曲信息的,而现在就可以了,想想为什么
.send_keys('你想输入的内容') # 模拟按键输入,自动填写表单
#你只需要定位到那个输入的框框那里,再用这个方法就可以往输入框里输入
.click() # 点击元素
#定位到能点的地方,基本上都能点
.clear() # 清空元素的内容
#清空你send_keys()里边输入的
更多的操作可以参见官方文档的交互动作介绍:这里
示例,打开百度搜索"Python":
# -*- coding: utf-8 -*- from selenium import webdriver import time from selenium.webdriver.common.keys import Keys driver = webdriver.Chrome() #设置浏览器 url = 'http://www.baidu.com' driver.get(url)#get(URL)是webdriver的一个方法,它的使命是为你打开指定URL的网页。 time.sleep(2)#由于浏览器缓冲加载网页需要耗费一些时间,等待1-2秒再去解析和提取比较稳妥。 #定位<input>标签 baidu = driver.find_elements_by_tag_name('input') #输入框是第7个 baidu[7].send_keys('Python') time.sleep(1) #搜索是第8个,并点击 baidu[8].click() # 也可以用下面的按下回车事件来代替点击搜索按钮 # baidu[7].send_keys(Keys.ENTER) time.sleep(3) driver.close()
需要Chrome升级到59版本及以上。
# 本地Chrome浏览器的静默默模式设置:
from selenium import webdriver #从selenium库中调用webdriver模块
from selenium.webdriver.chrome.options import Options # 从options模块中调用Options类
chrome_options = Options() # 实例化Option对象
chrome_options.add_argument('--headless') # 把Chrome浏览器设置为静默模式
driver = webdriver.Chrome(options = chrome_options) # 设置引擎为Chrome,在后台默默运行
这样浏览器就在后台默默运行,也不嫌我们挡着它。
例子:知乎大v张佳玮的文章“标题”、“摘要”、“链接”,并存储到本地文件。需要安装相关模块。上码看注释:
import requests import openpyxl from bs4 import BeautifulSoup import csv headers = { 'referer': 'https://www.zhihu.com/people/zhang-jia-wei/posts/posts_by_votes', 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.25 Safari/537.36' } #HTML里只放了两篇文章,然后去XHR里面找找看,有两个article的请求,在第二个找到了第一页的detail,可用json提取 #再比较各页参数,用循环写就可以获取多页的detail了 list1 = [] #用于储存detail n = 1 for i in range(3): #这里找两页,否则会给对方服务器造成很大压力 params = { 'include': 'data[*].comment_count,suggest_edit,is_normal,thumbnail_extra_info,thumbnail,can_comment,comment_permission,admin_closed_comment,content,voteup_count,created,updated,upvoted_followees,voting,review_info,is_labeled,label_info;data[*].author.badge[?(type=best_answerer)].topics', 'offset': str(i*20), 'limit': str(20), 'sort_by': 'voteups' } res = requests.get('https://www.zhihu.com/api/v4/members/zhang-jia-wei/articles',headers=headers,params=params) #print(res.status_code) detaillist = res.json() articlelist = detaillist['data'] for article in articlelist: # 把title、url、excerpt写成列表,后边用append函数一行行写入Excel list1.append([article['title'],article['url'],article['excerpt']]) #开始储存 #创建工作薄 wb = openpyxl.Workbook() #获取工作薄的活动表 sheet = wb.active #工作表重命名 sheet.title = 'zjw' #加表头,给A1单元格B1...赋值 sheet['A1'] = '文章标题' sheet['B1'] = '文章链接' sheet['C1'] = '摘要' for i in list1: sheet.append(i) #每次写入一行 wb.save('zhihuspider.xlsx') #记得保存格式为xlsx
然后在该py文件目录下,就会有一个zhihuspider.xlsx文件啦!
#或者用csv储存
csv_file = open('zhihuspider.csv','w',newline='',encoding='utf-8')
writer = csv.writer(csv_file) #用csv.writer()函数创建一个writer对象。
list2 = ['标题','链接','摘要']
#调用writer对象的writerow()方法,可以在csv文件里写入一行文字 “标题”和“链接”和"摘要"。
writer.writerow(list2)
for article in list1:
writer.writerow(article) #每次写入一行
csv_file.close()
————————每个人都在抱怨生活不易,可是都在默默为生活打拼————————
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。