python爬虫基础Ⅲ——selenium、数据存储



爬虫基础部分Ⅲ

上一部分了解了Ajax的分析和抓取方式,但有些网页比如淘宝,其Ajax接口含有很多加密参数,我们难以直接找出其规律,也很难直接分析Ajax来抓取。
为了解决这些问题,我们可以直接使用 模拟浏览器运行 的方式来实现,这样就可以做到在浏览器中看到的是什么样,抓取的源码就是什么样,也就是可见即可爬。这样就不用管网页内部的JS用了什么算法去渲染、加载页面,也不用管网页后台的Ajax接口到底有哪些参数。

selenium

懒得截图了(每次截图都弄不好TAT)

(1) selenium是什么

它是一个强大的库,首先你需要去安装它pip install selenium。它可以用几行代码,控制浏览器,做出自动打开、输入、点击等操作,就像是有一个真正的用户在操作一样。

而对于那些交互复杂、加密复杂的网站,selenium问题简化,爬动态网页如爬静态网页一样简单。

而关于动态网页和静态网页,其实你都已经接触过了。

前边第Ⅰ部分用html写出的网页,就是静态网页。我们使用BeautifulSoup爬取这类型网页,因为网页源代码中就包含着网页的所有信息(第0个请求里,在preview里就能看到所有信息),因此,网页地址栏的URL就是网页源代码的URL

后来在第Ⅱ部分,开始接触更复杂的网页,比如QQ音乐,要爬取的数据不在HTML源代码中,而是在json中,你就不能直接使用网址栏的URL了,而需要找到json数据的真实URL。这就是一种动态网页。

不论数据存在哪里,浏览器总是在向服务器发起各式各样的请求,当这些请求完成后,它们会一起组成开发者工具的Elements中所展示的,渲染完成的网页源代码。


(2) 好处与不足

在遇到页面交互复杂或是URL加密逻辑复杂的情况时,selenium就派上了用场,它可以真实地打开一个浏览器,等待所有数据都加载到Elements中之后,再把这个网页当做静态网页爬取就好了。

扫描二维码关注公众号,回复: 9048741 查看本文章

说了这么多优点,使用selenium时,当然也有美中不足之处。

由于要真实地运行本地浏览器,打开浏览器以及等待网渲染完成需要一些时间,selenium的工作不可避免地牺牲了速度和更多资源,不过,至少不会比人慢。


(3) 如何使用它

1. 下载浏览器驱动

首先呢你需要下载好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()

2. 设置浏览器引擎

# 本地Chrome浏览器设置方法
from selenium import webdriver #从selenium库中调用webdriver模块

driver = webdriver.Chrome() 
# 设置引擎为Chrome,真实地打开一个Chrome浏览器(然后赋值给变量driver,它就是一个实例化的浏览器)

3. 获取数据

我们前面使用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()

4.解析、提取数据

先回想下,使用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('你好')

5. 示例

还是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()

6. selenium 与 BS 的配合使用

先用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解析是爬不到歌曲信息的,而现在就可以了,想想为什么


7. selenium节点交互方法

.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()

8. 设置为无界面模式

需要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张佳玮的文章“标题”、“摘要”、“链接”,并存储到本地文件。需要安装相关模块。上码看注释:

(1) 写入xlsx文件

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文件啦!


(2) 写入csv文件

#或者用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()



————————每个人都在抱怨生活不易,可是都在默默为生活打拼————————

发布了16 篇原创文章 · 获赞 113 · 访问量 4892

猜你喜欢

转载自blog.csdn.net/qq_43280818/article/details/97045264
今日推荐