爬虫核心
- 步骤:
- 爬取整个网页
- 解析数据,解析网页数据,得到想要的数据
- 难点:
- 爬虫和反爬虫
反爬手段
- 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)