01 爬虫简介
- 爬虫:通过编写程序模拟浏览器上网,让其去互联网上抓取数据的过程。
- 技术中立,正当的爬虫:法律合法
- 遵守robots协议;优化代码,避免干扰被访问网站的正常运行;审查抓取的内容,如发现个人信息隐私或商业秘密等,应停止并删除
- 可实现爬虫的语言:php,c,c++,java,python
爬虫的分类:
通用爬虫:
- 通用爬虫是搜索引擎(Baidu、Google、Yahoo等)“抓取系统”的重要组成部分。主要目的是将互联网上的网页下载到本地,形成一个互联网内容的镜像备份。 简单来讲就是尽可能的;把互联网上的所有的网页下载下来,放到本地服务器里形成备分,在对这些网页做相关处理(提取关键字、去掉广告),最后提供一个用户检索接口。
聚焦爬虫:
- 聚焦爬虫是根据指定的需求抓取网络上指定的数据。例如:获取豆瓣上电影的名称和影评,而不是获取整张页面中所有的数据值。
增量式爬虫:
- 增量式是用来检测网站数据更新的情况,且可以将网站更新的数据进行爬取。
- 反爬机制
- 门户网站通过制定相应的策略和技术手段,防止爬虫程序进行网站数据的爬取。如:robots协议、UA检测等
- 反反爬策略
- 爬虫程序通过相应的策略和技术手段,破解门户网站的反爬虫手段,从而爬取到相应的数据
- robots协议
- robots.txt。即网站有权规定网站中哪些内容可以被爬虫抓取,哪些内容不可以被爬虫抓取。这样既可以保护隐私和敏感信息,又可以被搜索引擎收录、增加流量。
- HTTP协议是什么
- 概念:HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本地浏览器的传送协议。
- HTTP协议就是服务器(Server)和客户端(Client)之间进行数据交互(相互传输数据)的一种形式。(就像交流用的黑化)
- HTTP工作原理
- HTTP协议工作于客户端-服务端架构为上。浏览器作为HTTP客户端通过URL向HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收到的请求后,向客户端发送响应信息。
- 常见的请求头信息
accept | 浏览器通过这个头告诉服务器,它所支持的数据类型 |
Accept-Charset | 浏览器通过这个头告诉服务器,它支持哪种字符集 |
Accept-Encoding | 浏览器通过这个头告诉服务器,支持的压缩格式 |
Accept-Language | 浏览器通过这个头告诉服务器,它的语言环境 |
Host | 浏览器通过这个头告诉服务器,想访问哪台主机 |
If-Modified-Since | 浏览器通过这个头告诉服务器,缓存数据的时间 |
Referer | 浏览器通过这个头告诉服务器,客户机是哪个页面来的 防盗链 |
Connection | 浏览器通过这个头告诉服务器,请求完后是断开链接还是何持链接 |
X-Requested-With: | XMLHttpRequest 代表通过ajax方式进行访问 |
User-Agent | 请求载体的身份标识 |
- 常见的响应头信息
Location | 服务器通过这个头,来告诉浏览器跳到哪里 |
Server | 服务器通过这个头,告诉浏览器服务器的型号 |
Content-Encoding | 服务器通过这个头,告诉浏览器,数据的压缩格式 |
Content-Length | 服务器通过这个头,告诉浏览器回送数据的长度 |
Content-Language | 服务器通过这个头,告诉浏览器语言环境 |
Content-Type | 服务器通过这个头,告诉浏览器回送数据的类型 |
Refresh | 服务器通过这个头,告诉浏览器定时刷新 |
Content-Disposition | 服务器通过这个头,告诉浏览器以下载方式打数据 |
Transfer-Encoding | 服务器通过这个头,告诉浏览器数据是以分块方式回送的 |
Expires | -1 控制浏览器不要缓存 |
Cache-Control | no-cache |
Pragma | no-cache |
- HTTPS协议
- HTTPS (Secure Hypertext Transfer Protocol)安全超文本传输协议,HTTPS是在HTTP上建立SSL加密层,并对传输数据进行加密,是HTTP协议的安全版。
- https加密算法
- 对称秘钥加密:共享秘钥加密
- 非对称秘钥加密:私有密钥+公开密钥
- 证书秘钥加密:第三方机构——数字证书认证机构
02 requests模块
- Python实现爬虫的网络请求发送的模块:urlib requests
- requests模块是什么
- requests模块是python中原生的基于网络请求的模块,其主要作用是用来模拟浏览器发起请求。
- 功能强大,用法简洁,应用广泛
- requests模块的使用
- 环境安装:pip install requests
- 使用流程:
- 指定url
- 基于requests模块发送请求
- 获取响应对象中的数据值
- 持久化存储(非必须)
- 基于requests模块的get请求
- 需求:爬取搜狗指定词条对应的搜索结果页面(简易网页采集器)
- requests.get(url , params , headers).text
# 爬取搜狗页面首页的页面数据
import requests
if __name__ == '__main__':
# 1.指定url(网址)
url = 'https://www.sogou.com/'
# 2.发起request请求
response = requests.get(url=url)
# 3.获取响应数据.text(str)
page_text = response.text
print(page_text)
# 4.持久化存储
with open('./sogou.html', 'w', encoding="utf-8") as fp:
fp.write(page_text)
print("OVER!")
- 反爬机制
- User-Agent:请求载体的身份标识,使用浏览器发起的请求,请求载体的身份标识为浏览器,使用爬虫程序发起的请求,请求载体为爬虫程序。
- UA检测:相关的门户网站通过检测请求该网站的载体身份来辨别该请求是否为爬虫程序,如果是,则网站数据请求失败。因为正常用户对网站发起的请求的载体一定是基于某一款浏览器,如果网站检测到某一请求载体身份标识不是基于浏览器的,则让其请求失败。因此,UA检测是我们整个课程中遇到的第二种反爬机制,第一种是robots协议。
- UA伪装:通过修改/伪装爬虫请求的User-Agent来破解UA检测这种反爬机制
- 基于requests模块的post请求
import json
import requests
if __name__ == '__main__':
# UA伪装:将对应的User-Agent封装到一个字典中,伪装成一个浏览器
my_headers = {'User-Agent': '一个浏览器的user-agent'}
my_url = "https://fanyi.baidu.com/sug"
# 处理url携带的参数:封装到字典中
kw_word = input('enter a word:')
my_data = {'kw': kw_word}
# 对指定的url发起的请求对应的url是携带参数的,并且请求过程中处理了参数
response = requests.post(url=my_url, data=my_data, headers=my_headers)
dic_obj = response.json() # 返回的是字典对象
filename = kw_word + '.json'
fp = open(filename, 'w', encoding='utf-8')
json.dump(dic_obj, fp=fp, ensure_ascii=False)
print(filename, "保存成功")
print(dic_obj)
- requests.post():其中三个参数:url data headers
- 基于requests模块ajax的get请求
- requests.get(url, params, headers).json()
import json
import requests
if __name__ == '__main__':
# UA伪装:将对应的User-Agent封装到一个字典中,伪装成一个浏览器
headers = {'User-Agent': '一个浏览器的user-agent'}
my_url = "https://movie.douban.com/j/new_search_subjects"
# 处理url携带的参数:封装到字典中
my_param = {"sort": 'U', 'range': "0,10", 'tags': '', 'start': '20', 'genres': "动画"}
# 对指定的url发起的请求对应的url是携带参数的,并且请求过程中处理了参数
response = requests.get(url=my_url, params=my_param, headers=headers)
dict_obj = response.json()
filename = "douban.动画" + '.json'
fp = open(filename, 'w', encoding='utf-8')
json.dump(dict_obj, fp, ensure_ascii=False)
print(filename, "保存成功")
data_list = dict_obj['data']
data_new_list = []
for item_dict in data_list:
item_title = item_dict['title']
item_rate = item_dict['rate']
data_new_list.append((item_title, item_rate))
data_new_list.sort()
for item in data_new_list:
print(item)
- requests.get(“url params headers”).json()
- 基于requests模块ajax的post请
- requests.post(url, data, headers).json()
import json
import requests
if __name__ == '__main__':
# UA伪装:将对应的User-Agent封装到一个字典中,伪装成一个浏览器
my_headers = {'User-Agent': ''}
my_url = "http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=keyword"
"""对于一些post请求,url中“?”后面的不能省略。否则会不成功,且返回-1000"""
# 处理url携带的参数:封装到字典中
my_data = {'cname': '', 'pid': '', 'keyword': "哈尔滨", 'pageIndex': '1', 'pageSize': '20'}
# 对指定的url发起的请求对应的url是携带参数的,并且请求过程中处理了参数
response = requests.post(url=my_url, data=my_data, headers=my_headers)
dict_obj = response.json()
filename = my_data['keyword'] + "地肯德基餐厅查询" + '.json'
fp = open(filename, 'w', encoding='utf-8')
json.dump(dict_obj, fp, ensure_ascii=False)
print(filename, "保存成功")
data_list = dict_obj['Table1']
for item_dict in data_list:
item_storeName = item_dict['storeName']
item_addressDetail = item_dict['addressDetail']
print(item_storeName, item_addressDetail)
03 数据解析
数据爬取流程
- 指定url
- 发起请求
- 获取响应数据
- 数据解析
- 持久化存储
python中如何实现数据解析
- 正则表达式
- bs4解析
- xpath解析
数据解析原理概述:
- 解析的局部文本内容都会在 标签之间或者标签对应的属性中进行存储
- 进行制定标签的定位
- 标签或者标签对应属性中存储数据的提取(解析)
数据解析——正则表达式
- 常用正则表达式:
- 爬取煎蛋百科中图片
import requests
import re
import os
if __name__ == '__main__':
url = 'http://jandan.net/ooxx'
headers = {
#定制请求头中的User-Agent参数,当然也可以定制请求头中其他的参数
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36',
}
#创建文件
if not os.path.exists('./pics'):
os.mkdir('./pics')
#使用通用爬虫爬取整张页面
page_text=requests.get(url=url,headers=headers).text
#使用聚焦爬虫
ex = '<img src="(.*?)".*?>'
img_src_list = re.findall(ex,page_text,re.S)
for img_src in img_src_list:
img_src_url = 'https:'+img_src
pic_bytes=requests.get(url=img_src_url,headers=headers).content
pic_name = img_src_url.split('/')[-1]
pic_path = './pics/'+ pic_name
with open(pic_path,'wb') as f:
f.write(pic_bytes)
print(pic_name,'ok!')
- 问题:(tbc)
数据解析——bs4
安装:
- 终端中输入:pip install bs4
- 终端中输入:pip install lxml
使用流程:
- 导包:from bs4 import BeautifulSoup
- 使用方式:可以将一个html文档,转化为BeautifulSoup对象,然后通过对象的方法或者属性去查找指定的节点内容
(1)转化本地文件: soup = BeautifulSoup(open('本地文件'), 'lxml')
(2)转化网络文件:soup = BeautifulSoup('字符串类型或者字节类型', 'lxml')
(3)打印soup对象显示内容为html文件中的内容
基础巩固
- (1)根据标签名查找
- soup.a 只能找到第一个符合要求的标签
- (2)获取属性
- soup.a.attrs 获取a所有的属性和属性值,返回一个字典
- soup.a.attrs['href'] 获取href属性
- soup.a['href'] 也可简写为这种形式
- (3)获取内容
- soup.a.string
- soup.a.text
- soup.a.get_text()
- 【注意】如果标签还有标签,那么string获取到的结果为None,而其它两个,可以获取文本内容
- (4)find:找到第一个符合要求的标签 - soup.find('a') 找到第一个符合要求的
- soup.find('a', title="xxx")
- soup.find('a', alt="xxx")
- soup.find('a', class_="xxx") - soup.find('a', id="xxx")
- (5)find_all:找到所有符合要求的标签
- soup.find_all('a') - soup.find_all(['a','b']) 找到所有的a和b标签
- soup.find_all('a', limit=2) 限制前两个
- (6)根据选择器选择指定的内容 select:soup.select('#feng')
- 常见的选择器:标签选择器(a)、类选择器(.)、id选择器(#)、层级选择器
- 层级选择器: div .dudu #lala .meme .xixi 下面好多级
- div > p > a > .lala 只能是下面一级
- 【注意】select选择器返回永远是列表,需要通过下标提取指定的对象
项目巩固:
- 使用bs4实现将诗词名句网站中三国演义小说的每一章的内容爬去到本地磁盘进行存储
- 代码实现
- tbc