Python爬虫基础(一):urllib库的使用详解

系列文章索引

Python爬虫基础(一):urllib库的使用详解
Python爬虫基础(二):使用xpath与jsonpath解析爬取的数据
Python爬虫基础(三):使用Selenium动态加载网页
Python爬虫基础(四):使用更方便的requests库
Python爬虫基础(五):使用scrapy框架

一、urllib库的使用

1、基本介绍

urllib是一个python自带的库,不需要手动安装。

urllib库用于操作网页 URL,并对网页的内容进行抓取处理。

urllib 包 包含以下几个模块:
urllib.request - 打开和读取 URL。
urllib.error - 包含 urllib.request 抛出的异常。
urllib.parse - 解析 URL。
urllib.robotparser - 解析 robots.txt 文件

python爬虫主要用到的urllib库中的request和parse模块

# 使用urllib来获取百度首页的源码,引入urllib的request
import urllib.request

# (1)定义一个url  就是你要访问的地址
url = 'http://www.baidu.com'

# (2)模拟浏览器向服务器发送请求 response响应
response = urllib.request.urlopen(url)

# (3)获取响应中的页面的源码  content 内容的意思
# read方法  返回的是字节形式的二进制数据
# 我们要将二进制的数据转换为字符串
# 二进制 --> 字符串  解码:  decode('编码的格式')
content = response.read().decode('utf-8')

# (4)打印数据,返回的内容就是源地址的html内容
print(content)

2、response的类型和关键方法

一个类型: http.client.HTTPResponse
六个方法: read readline readlines getcode geturl getheaders

import urllib.request

url = 'http://www.baidu.com'

# 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(url)

# 一个类型和六个方法
# response是HTTPResponse的类型:<class 'http.client.HTTPResponse'>
# print(type(response))

# 按照一个字节一个字节的去读
# content = response.read()
# print(content)

# 返回固定数量的字节
# content = response.read(5)
# print(content)

# 读取一行
# content = response.readline()
# print(content)

# 读取所有的行
# content = response.readlines()
# print(content)

# 返回状态码  如果是200 那么就证明请求成功
# print(response.getcode())

# 返回的是url地址
# print(response.geturl())

# 获取是一个状态信息,响应头
# print(response.getheaders())

3、下载文件

import urllib.request

# 下载网页
# url_page = 'http://www.baidu.com'

# url代表的是下载的路径  filename文件的名字
# 在python中 可以变量的名字  也可以直接写值
# urllib.request.urlretrieve(url_page,'baidu.html')

# 下载图片
url_img = 'https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png'
urllib.request.urlretrieve(url= url_img,filename='baidu.jpg')

# 下载视频
url_video = 'https://highlight-video.cdn.bcebos.com/video/6s/b1bc17fc-46dd-11ee-911e-7cd30a602444.mp4?v_from_s=bdapp-landingpage-api-nanjing'
urllib.request.urlretrieve(url_video,'video.mp4')

4、GET请求实例

(1)设置请求头(百度)

ua反爬虫是一种很常见的反爬手段,通过识别发送的请求中是否有需要的参数信息来判断这次访问是否由用户通过浏览器发起。

UA介绍:User Agent中文名为用户代理,简称 UA,它是一个特殊字符串头,使得服务器能够识别客户使用的操作系统及版本、CPU 类型、浏览器及版本。浏览器内核、浏览器渲染引擎、浏览器语言、浏览器插件等。

import urllib.request

url = 'https://www.baidu.com'

headers = {
    
    
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}


# 请求对象的定制,手动设置请求头
# 需要手动指定url和headers,因为Request对象的构造方法,参数的顺序并不是这样,需要关键字传参
request = urllib.request.Request(url=url,headers=headers)

response = urllib.request.urlopen(request)

content = response.read().decode('utf8')

print(content)

(2)使用quote方法对get参数编码(百度)

使用urllib.parse.quote,将中文编码为unicode格式,拼接到url上使其作为get请求的参数。

import urllib.request
import urllib.parse


url = 'https://www.baidu.com/s?wd='

# 请求对象的定制为了解决反爬的第一种手段
headers = {
    
    
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
    'Cookie' : ''
}

# 将周杰伦三个字变成unicode编码的格式
# 我们需要依赖于urllib.parse
name = urllib.parse.quote('周杰伦')

url = url + name
print(url) # https://www.baidu.com/s?wd=%E5%91%A8%E6%9D%B0%E4%BC%A6

# 请求对象的定制
request = urllib.request.Request(url=url,headers=headers)

# 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(request)

# 获取响应的内容
content = response.read().decode('utf-8')

# 打印数据
print(content)

(3)使用urlencode方法对get多个参数编码(百度)

使用urllib.parse.urlencode方法,将字典进行自动编码为get请求参数。

import urllib.request
import urllib.parse

base_url = 'https://www.baidu.com/s?'

# 使用字典
data = {
    
    
    'wd':'周杰伦',
    'sex':'男',
    'location':'中国台湾省'
}

# 自动将字典,拼接为url,并且加上&,并且自动转码
new_data = urllib.parse.urlencode(data)
print(new_data) # wd=%E5%91%A8%E6%9D%B0%E4%BC%A6&sex=%E7%94%B7&location=%E4%B8%AD%E5%9B%BD%E5%8F%B0%E6%B9%BE%E7%9C%81

# 请求资源路径
url = base_url + new_data

headers = {
    
    
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/86.0.4240.198 Safari/537.36',
    'Cookie' : ''
}

# 请求对象的定制
request = urllib.request.Request(url=url,headers=headers)

# 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(request)

# 获取网页源码的数据
content = response.read().decode('utf-8')

# 打印数据
#print(content)

(4)get请求结果保存本地(豆瓣电影)

# get请求
# 获取豆瓣电影的第一页的数据 并且保存起来

import urllib.request

url = 'https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&start=0&limit=20'

headers = {
    
    
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}

# (1) 请求对象的定制
request = urllib.request.Request(url=url,headers=headers)

# (2)获取响应的数据
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')

# (3) 数据下载到本地
# open方法默认情况下使用的是gbk的编码  如果我们要想保存汉字 那么需要在open方法中指定编码格式为utf-8
# encoding = 'utf-8'
# fp = open('douban.json','w',encoding='utf-8')
# fp.write(content)

with open('douban1.json','w',encoding='utf-8') as fp:
    fp.write(content)

(5)get请求结果保存本地2(豆瓣电影)

# https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&
# start=0&limit=20

# https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&
# start=20&limit=20

# https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&
# start=40&limit=20

# https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&
# start=60&limit=20

# page    1  2   3   4
# start   0  20  40  60

# start (page - 1)*20


# 下载豆瓣电影前10页的数据
# (1) 请求对象的定制
# (2) 获取响应的数据
# (3) 下载数据

import urllib.parse
import urllib.request

def create_request(page):
    base_url = 'https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&'

    data = {
    
    
        'start':(page - 1) * 20,
        'limit':20
    }

    data = urllib.parse.urlencode(data)

    url = base_url + data

    headers = {
    
    
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
    }

    request = urllib.request.Request(url=url,headers=headers)
    return request


def get_content(request):
    response = urllib.request.urlopen(request)
    content = response.read().decode('utf-8')
    return content


def down_load(page,content):
    with open('douban_' + str(page) + '.json','w',encoding='utf-8')as fp:
        fp.write(content)

# 程序的入口
if __name__ == '__main__':
    start_page = int(input('请输入起始的页码'))
    end_page = int(input('请输入结束的页面'))

    for page in range(start_page,end_page+1):
#         每一页都有自己的请求对象的定制
        request = create_request(page)
#         获取响应的数据
        content = get_content(request)
#         下载
        down_load(page,content)

5、POST请求实例

(1)POST请求发送数据(百度翻译)

post请求方式的参数 必须编码 data = urllib.parse.urlencode(data)
编码之后 必须调用encode方法 data = urllib.parse.urlencode(data).encode(‘utf-8’)
参数是放在请求对象定制的方法中 request = urllib.request.Request(url=url,data=data,headers=headers)

# post请求,百度翻译

import urllib.request
import urllib.parse


url = 'https://fanyi.baidu.com/sug'

headers = {
    
    
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}

# 请求信息,格式为FormData
data = {
    
    
    'kw':'spider'
}

# post请求的参数 必须要进行编码
data = urllib.parse.urlencode(data).encode('utf-8')

# post的请求的参数 是不会拼接在url的后面的  而是需要放在请求对象定制的参数中
# post请求的参数 必须要进行编码
request = urllib.request.Request(url=url,data=data,headers=headers)

# 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(request)

# 获取响应的数据
content = response.read().decode('utf-8')

# 解析 字符串 --> json对象
import json

obj = json.loads(content)
print(obj)
# 百度详细翻译
import urllib.request
import urllib.parse

url = 'https://fanyi.baidu.com/v2transapi?from=en&to=zh'

headers = {
    
    
    # 'Accept': '*/*',
    # 'Accept-Encoding': 'gzip, deflate, br',
    # 'Accept-Language': 'zh-CN,zh;q=0.9',
    # 'Connection': 'keep-alive',
    # 'Content-Length': '135',
    # 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
    'Cookie': 'BIDUPSID=xxxxxxxxxxxxxxxxxxxxxx; PSTM=xxxxxxxxx;xxxxxxxxxxxxxxxxxxxxxxxxxx',
    # 'Host': 'fanyi.baidu.com',
    # 'Origin': 'https://fanyi.baidu.com',
    # 'Referer': 'https://fanyi.baidu.com/?aldtype=16047',
    # 'sec-ch-ua': '"Chromium";v="92", " Not A;Brand";v="99", "Google Chrome";v="92"',
    # 'sec-ch-ua-mobile': '?0',
    # 'Sec-Fetch-Dest': 'empty',
    # 'Sec-Fetch-Mode': 'cors',
    # 'Sec-Fetch-Site': 'same-origin',
    # 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
    # 'X-Requested-With': 'XMLHttpRequest',
}

data = {
    
    
    'from': 'en',
    'to': 'zh',
    'query': 'love',
    'transtype': 'realtime',
    'simple_means_flag': '3',
    'sign': '198772.518981',
    'token': '5483bfa652979b41f9c90d91f3de875d',
    'domain': 'common',
}
# post请求的参数  必须进行编码 并且要调用encode方法
data = urllib.parse.urlencode(data).encode('utf-8')

# 请求对象的定制
request = urllib.request.Request(url = url,data = data,headers = headers)

# 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(request)

# 获取响应的数据
content = response.read().decode('utf-8')

import json

obj = json.loads(content)
print(obj)

(2)POST请求结果保存本地(肯德基)

# 1页
# http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname
# post
# cname: 北京
# pid:
# pageIndex: 1
# pageSize: 10


# 2页
# http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname
# post
# cname: 北京
# pid:
# pageIndex: 2
# pageSize: 10

import urllib.request
import urllib.parse

def create_request(page):
    base_url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname'

    data = {
    
    
        'cname': '北京',
        'pid':'',
        'pageIndex': page,
        'pageSize': '10'
    }

    data = urllib.parse.urlencode(data).encode('utf-8')

    headers = {
    
    
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
    }

    request = urllib.request.Request(url=base_url,headers=headers,data=data)

    return request

def get_content(request):
    response = urllib.request.urlopen(request)
    content = response.read().decode('utf-8')
    return content


def down_load(page,content):
    with open('kfc_' + str(page) + '.json','w',encoding='utf-8')as fp:
        fp.write(content)



if __name__ == '__main__':
    start_page = int(input('请输入起始页码'))
    end_page = int(input('请输入结束页码'))

    for page in range(start_page,end_page+1):
        # 请求对象的定制
        request = create_request(page)
        # 获取网页源码
        content = get_content(request)
        # 下载
        down_load(page,content)

6、异常处理

(1)URLError\HTTPError简介

1.HTTPError类是URLError类的子类
2.导入的包urllib.error.HTTPError urllib.error.URLError
3.http错误:http错误是针对浏览器无法连接到服务器而增加出来的错误提示。引导并告诉浏览者该页是哪里出了问题。
4.通过urllib发送请求的时候,有可能会发送失败,这个时候如果想让你的代码更加的健壮,可以通过try‐except进行捕获异常,异常有两类,URLError\HTTPError

(2)URLError\HTTPError实例

import urllib.request
import urllib.error

url = 'https://blog.csdn.net/sulixu/article/details/1198189491'

# url = 'http://www.doudan.com'

headers = {
    
    
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}

try:
    request = urllib.request.Request(url = url, headers = headers)

    response = urllib.request.urlopen(request)

    content = response.read().decode('utf-8')

    print(content)
# 404等状态码,会抛出HTTPError
except urllib.error.HTTPError:
    print('系统正在升级。。。')

# url等其他问题,会抛出URLError
except urllib.error.URLError:
    print('我都说了 系统正在升级。。。')

7、实操:爬取微博好友圈的内容

(1)找到好友圈的get接口

通过浏览器的F12,我们点击好友圈之后,发现调用了这样一个接口,通过Preview查看返回的数据,发现正是好友圈的内容。
在这里插入图片描述
在这里插入图片描述

(2)编码爬取数据

import urllib.request

url = 'https://weibo.com/ajax/feed/groupstimeline?list_id=100095458128744&refresh=4&fast_refresh=1&count=25'

# 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(url)

# 获取响应的数据
content = response.read().decode('utf-8')

# 将数据保存到本地
with open('weibo.json','w',encoding='utf-8') as fp:
    fp.write(content)

运行上述代码,我们发现,控制台出现了错误:

content = response.read().decode(‘utf-8’)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
UnicodeDecodeError: ‘utf-8’ codec can’t decode byte 0xca in position 339: invalid continuation byte

代码稍微修改一下,打印read读取的结果:

# 获取响应的数据
content = response.read()
print(content)

发现返回的是一个html信息,charset编码格式是gb2312:
在这里插入图片描述
然后修改代码,将生成的html保存下来:

# 获取响应的数据
content = response.read().decode('gb2312')

# 将数据保存到本地
with open('weibo.html','w',encoding='gb2312') as fp:
    fp.write(content)

我们发现,并不是我们想要的数据。

这是因为,爬取微博好友圈的内容,需要登录,我们缺少了关键的信息。

我们加上请求头,并设置Cookie尝试一下:
在这里插入图片描述

import urllib.request

url = 'https://weibo.com/ajax/feed/groupstimeline?list_id=100095458128744&refresh=4&fast_refresh=1&count=25'

headers = {
    
    
	#     cookie中携带着你的登陆信息   如果有登陆之后的cookie  那么我们就可以携带着cookie进入到任何页面
	'cookie': '拷贝浏览器中的cookie',
}
# 请求对象的定制
request = urllib.request.Request(url=url,headers=headers)

# 模拟浏览器向服务器发送请求
response = urllib.request.urlopen(request)

# 获取响应的数据
content = response.read().decode('utf-8')

# 将数据保存到本地
with open('weibo.json','w',encoding='utf-8') as fp:
    fp.write(content)

我们发现,成功获取到了数据!

8、Handler处理器

(1)基本使用

# 需求 使用handler来访问百度  获取网页源码

import urllib.request

url = 'http://www.baidu.com'

headers = {
    
    
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}

request = urllib.request.Request(url = url,headers = headers)

# handler   build_opener  open

# (1)获取hanlder对象
handler = urllib.request.HTTPHandler()

# (2)获取opener对象
opener = urllib.request.build_opener(handler)

# (3) 调用open方法
response = opener.open(request)

content = response.read().decode('utf-8')

print(content)

(2)使用代理

代理的常用功能:
1.突破自身IP访问限制,访问国外站点。
2.访问一些单位或团体内部资源
扩展:某大学FTP(前提是该代理地址在该资源的允许访问范围之内),使用教育网内地址段免费代理服务器,就可以用于对教育网开放的各类FTP下载上传,以及各类资料查询共享等服务。
3.提高访问速度
扩展:通常代理服务器都设置一个较大的硬盘缓冲区,当有外界的信息通过时,同时也将其保存到缓冲区中,当其他用户再访问相同的信息时, 则直接由缓冲区中取出信息,传给用户,以提高访问速度。
4.隐藏真实IP
扩展:上网者也可以通过这种方法隐藏自己的IP,免受攻击。

import urllib.request

url = 'http://www.baidu.com/s?wd=ip'

headers = {
    
    
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}

# 请求对象的定制
request = urllib.request.Request(url = url,headers= headers)

# 模拟浏览器访问服务器
# response = urllib.request.urlopen(request)

proxies = {
    
    
    'http':'192.168.56.10:5556'
}
# handler  build_opener  open
# 开启代理
handler = urllib.request.ProxyHandler(proxies = proxies)

opener = urllib.request.build_opener(handler)

response = opener.open(request)

# 获取响应的信息
content = response.read().decode('utf-8')

# 保存
with open('daili.html','w',encoding='utf-8')as fp:
    fp.write(content)

(3)使用代理池

import urllib.request
# 多个代理
proxies_pool = [
    {
    
    'http':'192.168.56.10:5556'},
    {
    
    'http':'192.168.56.10:5557'},
]

import random
# 随机选择一个
proxies = random.choice(proxies_pool)

url = 'http://www.baidu.com/s?wd=ip'

headers = {
    
    
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'
}

request = urllib.request.Request(url = url,headers=headers)

handler = urllib.request.ProxyHandler(proxies=proxies)

opener = urllib.request.build_opener(handler)

response = opener.open(request)

content = response.read().decode('utf-8')

with open('daili.html','w',encoding='utf-8')as fp:
    fp.write(content)

猜你喜欢

转载自blog.csdn.net/A_art_xiang/article/details/132686669