爬虫核心
- 步骤:
- 爬上整个网页
- 分析数据,分析网页数据,得到想要的数据
- 难点:
- 爬虫和反爬虫
反爬手段
- user-angent
- 服务器可以识别客户端的操作系统,cpu、浏览器版本等
- 服务器通过此数据识别客户端是机器还是人
- 代理ip
- 判断是否有不同于人类的行为(比如每秒点击次数过多),服务器会在这个时候给客户端ip封了
- 验证码访问
- 动态加载网页
- 网页返回js数据,不是真实数据
- 数据加密
爬虫常用库
urllib
- 功能:
- 模拟浏览器向服务器发送请求
基本用法
- 用法:
-
# 使用urllib获取百度首页源码 import urllib.request # 定义一个url url = 'http://www.baidu.com' # 模拟浏览器向服务器发送请求 response 响应 response = urllib.request.urlopen(url) # 在响应中获取页面源码 # read 该方法以字节形式返回二进制数据,二进制形式需要转换为字符串,即解码decode(‘编码格式’) content = response.read() # 打印数据 print(content)
执行后获得的数据如下
-
我们发现百度网盘的源代码写在前面b,而且源代码中没有像百度这样的中文,因为read()函数返回的是二进制形式的内容,需要加decode来解码
-
decode(‘编码类型’)编码类型的确定方法:
-
打开百度搜索网页源码, 找到charset
-
后面的内容是编码类型
-
-
- 修改后的代码如下:
-
# 使用urllib获取百度首页源码 import urllib.request # 定义一个url url = 'http://www.baidu.com' # 模拟浏览器向服务器发送请求 response 响应 response = urllib.request.urlopen(url) # 在响应中获取页面源码 # read 该方法以字节形式返回二进制数据,二进制形式需要转换为字符串,即解码decode(‘编码格式’) content = response.read().decode('utf-8') # 打印数据 print(content)
此时可以获得正常的网页源码。
-
urllib中的read、readline、readlines以及get方法等
-
-
import urllib.request url = 'http://www.baidu.com' #模拟服务器发送请求 response = urllib.request.urlopen(url) # 一种类型和六种方法 # response 是httpresponse类型 print(type(response)) # read方法按字节读取,读取速度慢 # content = response.read() #print(content) # read参数表示只读n个字节 # content = response.read(5) # print(content) # 只能读一行 # content = response.readline() # print(content) # 读取所有行,每次读一行,速度更快 # content = response.readlines() # print(content) # 如果是200,返回状态码,证明网页获取成功 print(response.getcode()) # 返回url地址 print(response.geturl()) # headers状态信息 print(response.getheaders()) # 一个类型 HTTPResponse # 六个方法 read readline readlines getcode geturl getheaders
-
urllib下载
import urllib.request # 下载网页 url_page = 'http://www.baidu.com' # url 下载路径 # filename 文件名 urllib.request.urlretrieve(url_page, 'baidu.html') # 下载图片 url_img = 'https://img2.baidu.com/it/u=331121307,2721562722&fm=253&fmt=auto&app=138&f=JPEG?w=561&h=500' urllib.request.urlretrieve(url_img, 'lisa.JPEG') # 下载视频 url_video = 'https://vd4.bdstatic.com/mda-nanqpmhz0dr117g2/720p/h264_delogo/1642958778335147109/mda-nanqpmhz0dr117g2.mp4?v_from_s=hkapp-haokan-nanjing&auth_key=1643037477-0-0-68fb4cfd705f21ff3e5482ff469aeda7&bcevod_channel=searchbox_feed&pd=1&pt=3&logid=2877641603&vid=9060722192467841255&abtest=3000212_5&klogid=2877641603' urllib.request.urlretrieve(url_video, 'xinwen.mp4')
获取网页链接的方式有:
删除后的内容是代码中使用的内容
获取图片链接的方式如下:
获取视频链接的方式如下:
user agent(ua)反爬措施(请求定制对象)
爬百度首页网页源码时,输入http://www.baidu.com可获得完整的源码,输入https://www.baidu.com得到的是不完整的源代码,这是user agent服务器可以知道客户端的浏览器版本,cpu大小等信息。
import urllib.request url = 'https://www.baidu.com' # url 的组成 # https://www.baidu.com/s?wd=周杰伦 # 协议 主机 端口号 路径 参数 锚点
# http/https www.bidu.com 80/443 s wd=周杰伦
# http 80
# https 443
# mysql 3306
# oracle 1521
# redis 6379
# mongodb 27017
response = urllib.request.urlopen(url)
content = response.read().decode('utf-8')
print(content)
查看网页ua的方法:
首先打开网页,然后右键-检查(inspect)(或者直接点击fn+f12)
点击network - f5刷新 - 点击www.baidu.com - 查看headers中最后一部分 - 查看user agent
那么在爬取的时候只需要传入ua参数就可以爬取内容了
import urllib.request
url = 'https://www.baidu.com'
# url 的组成
# https://www.baidu.com/s?wd=周杰伦
# 协议 主机 端口号 路径 参数 锚点
# http/https www.bidu.com 80/443 s wd=周杰伦
# http 80
# https 443
# mysql 3306
# oracle 1521
# redis 6379
# mongodb 27017
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.71 Safari/537.36'
}
# urlopen方法中不能传入字典
# 请求对象的定制
# Request里面的参数是url = url headers = headers 的原因是Requese的参数是url data headers所以这里的传参要特别说明
request = urllib.request.Request(url=url, headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)
get请求的quote方法
首先看下面这段代码
# https://www.baidu.com/s?wd=%E5%91%A8%E6%9D%B0%E4%BC%A6
# 需求 获取网页源码
import urllib.request
url = 'https://www.baidu.com/s?wd=周杰伦'
# 请求对象定制,解决ua
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36'
}
request = urllib.request.Request(url = url, headers = headers)
# 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(request)
# 获取响应的内容
content = response.read().decode('utf-8')
# 打印数据
print(content)
这段代码会直接报错,可以看到这段代码和前面那段代码唯一的区别就是url中wd=后面的内容,这段代码用了unicode码,而上一段用了ASCII码。实际上url中用的解码方式是ASCII码,所以这段报了错,那么如何解决这个问题哪?
答案就是quote方法,其可以将汉字转化为unicode编码
修改之后的代码如下
# https://www.baidu.com/s?wd=%E5%91%A8%E6%9D%B0%E4%BC%A6
# 需求 获取网页源码
import urllib.request
import urllib.parse
url = 'https://www.baidu.com/s?wd='
# 请求对象定制,解决ua
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36'
}
# 将周杰伦编程unicode编码格式
name = urllib.parse.quote('周杰伦')
print(name)
print(url)
url = url + name
print(url)
request = urllib.request.Request(url = url, headers = headers)
# 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(request)
# 获取响应的内容
content = response.read().decode('utf-8')
# 打印数据
print(content)
get方法的urlencode方法
上面的quote方法在传入参数有多个的时候是比较麻烦的,需要进行多次拼接。解决方法是:
# urlencode 用于多参数场景
import urllib.request
import urllib.parse
# https://www.baidu.com/s?wd=周杰伦&sex=男
data = {
'wd':'周杰伦',
'sex':'男',
'location':'台湾'
}
a = urllib.parse.urlencode(data)
print(a)
上面这段代码的输出为:
完整代码如下:
# urlencode 用于多参数场景
import urllib.request
import urllib.parse
# https://www.baidu.com/s?wd=周杰伦&sex=男
base_url = 'https://www.baidu.com/s?'
data = {
'wd':'周杰伦',
'sex':'男',
'location':'台湾'
}
new_data = urllib.parse.urlencode(data)
# 请求资源路径
url = base_url + new_data
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/97.0.4692.99 Safari/537.36'
}
# 请求对象的定制
request = urllib.request.Request(url=url, headers = headers)
# 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(request)
# 获取网页源码的数据
content = response.read().decode('utf-8')
print(content)