zl程序教程

您现在的位置是:首页 >  后端

当前栏目

Python之Urllib使用

Python urllib 使用
2023-09-27 14:29:07 时间

1. 什么是互联网爬虫?

在这里插入图片描述

如果我们把互联网比作一张大的蜘蛛网,那一台计算机上的数据便是蜘蛛网上的一个猎物,而爬虫程序就是一只小

蜘蛛,沿着蜘蛛网抓取自己想要的数据

解释1:通过一个程序,根据Url(http://www.taobao.com)进行爬取网页,获取有用信息 
解释2:使用程序模拟浏览器,去向服务器发送请求,获取响应信息

2. 爬虫核心?

  1. 爬取网页:爬取整个网页 包含了网页中所有得内容

  2. 解析数据:将网页中你得到的数据 进行解析

  3. 难点:爬虫和反爬虫之间的博弈

3. 爬虫的用途?

  • 数据分析/人工数据集

  • 社交软件冷启动

  • 舆情监控

  • 竞争对手监控

4. 爬虫分类?

通用爬虫: 
   实例 
      百度、360、google、sougou等搜索引擎‐‐‐伯乐在线 
   功能 
      访问网页‐>抓取数据‐>数据存储‐>数据处理‐>提供检索服务 
   robots协议 
      一个约定俗成的协议,添加robots.txt文件,来说明本网站哪些内容不可以被抓取,起不到限制作用 自己写的       爬虫无需遵守 
   网站排名(SEO) 
      1. 根据pagerank算法值进行排名(参考个网站流量、点击率等指标) 
      2. 百度竞价排名 
   缺点 
      1. 抓取的数据大多是无用的 
      2.不能根据用户的需求来精准获取数据
聚焦爬虫
    功能 
       根据需求,实现爬虫程序,抓取需要的数据 
    设计思路
       1.确定要爬取的url 
          如何获取Url 
       2.模拟浏览器通过http协议访问url,获取服务器返回的html代码 
          如何访问 
       3.解析html字符串(根据一定规则提取需要的数据) 
          如何解析

5. 反爬手段

  1. User‐Agent:

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

    • 西次代理
    • 快代理
    • 什么是高匿名、匿名和透明代理?它们有什么区别?
      • 使用透明代理,对方服务器可以知道你使用了代理,并且也知道你的真实IP。
      • 使用匿名代理,对方服务器可以知道你使用了代理,但不知道你的真实IP。
      • 使用高匿名代理,对方服务器不知道你使用了代理,更不知道你的真实IP。
  3. 验证码访问

    • 打码平台

      • 云打码平台

      • 超级🦅

  4. 动态加载网页 网站返回的是js数据 并不是网页的真实数据

    • selenium驱动真实的浏览器发送请求
  5. 数据加密

    • 分析js代码

6. urllib库使用

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

response 服务器返回的数据

  • response的数据类型是HttpResponse

  • 字节‐‐>字符串 解码decode

  • 字符串‐‐>字节 编码encode

  • read() 字节形式读取二进制 扩展:rede(5)返回前几个字节

  • readline() 读取一行

  • readlines() 一行一行读取 直至结束

  • getcode() 获取状态码

  • geturl() 获取url

  • getheaders() 获取headers

  • urllib.request.urlretrieve()

    • 请求网页
    • 请求图片
    • 请求视频

基本使用:

爬取百度首页源码:

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

# 定义一个url
url = 'http://www.baidu.com'

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

# 获取响应中的页面源码
# read方法,返回的是字节形式的二进制数据
# 将二进制数据转换为字符串
# 二进制 =》字符串 解码 decode('编码格式'),编码格式在页面的head标签meta的charset属性
content = response.read().decode('utf-8')

print(content)

一个类型和六个方法:

import urllib.request

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

response = urllib.request.urlopen(url)

# response 是HTTPResponse类型
# print(type(response))

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

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

# content = response.readlines()

# 返回状态码,如果是200,就证明证明没有错
# print(response.getcode())

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

# 获取的是一些状态信息
print(response.getheaders())

下载:

import urllib.request

# 下载一个网页
# url_page = 'http://www.baidu.com'
# urllib.request.urlretrieve(url_page, 'baidu.html')

# 下载图片
# url_img = 'https://img-home.csdnimg.cn/images/20201124032511.png'
# urllib.request.urlretrieve(url=url_img, filename='csdn.jpg')

# 下载视频
url_video = 'https://vd2.bdstatic.com/mda-jmsy151cd1ijyz3r/hd/mda-jmsy151cd1ijyz3r.mp4?v_from_s=hkapp-haokan-hnb&auth_key=1656516999-0-0-1fcd521c8a93ff8141ca1645aa7c315c&bcevod_channel=searchbox_feed&pd=1&cd=0&pt=3&logid=0398986023&vid=3985750168738470460&abtest=102784_2-102836_3-102982_3-3000232_2&klogid=0398986023'
urllib.request.urlretrieve(url_video, 'test.mp4')

7. 请求对象的定制

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

语法:request = urllib.request.Request()

示例:

import urllib.request

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

# headers详情见下边图片
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}

# 因为参数顺序的问题,需要关键字传参
request = urllib.request.Request(url=url, headers=headers)

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

print(content)

在这里插入图片描述

编码的由来:

由于计算机是美国人发明的,因此,最早只有127个字符被编码到计算机里,也就是大小写英文字母、数字和一些符号, 这个编码表被称为ASCII编码,比如大写字母A的编码是65,小写字母z的编码是122。 但是要处理中文显然一个字节是不够的,至少需要两个字节,而且还不能和ASCII编码冲突, 所以,中国制定了GB2312编码,用来把中文编进去。 你可以想得到的是,全世界有上百种语言,日本把日文编到Shift_JIS里,韩国把韩文编到Euc‐kr里, 各国有各国的标准,就会不可避免地出现冲突,结果就是,在多语言混合的文本中,显示出来会有乱码。 因此,Unicode应运而生。Unicode把所有语言都统一到一套编码里,这样就不会再有乱码问题了。 Unicode标准也在不断发展,但最常用的是用两个字节表示一个字符(如果要用到非常偏僻的字符,就需要4个字节)。 现代操作系统和大多数编程语言都直接支持Unicode。

8. 编解码

1.get请求方式:urllib.parse.quote()

import urllib.request
import urllib.parse

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

# 把参数转为ASCII编码
url += url + urllib.parse.quote('周杰伦')

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

response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)

2. get请求方式:urllib.parse.urlencode()

import urllib.request
import urllib.parse

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

# 利用字典类型编码传参
data = {
    'wd': '蔡依林',
    'sex': '女'
}
url += urllib.parse.urlencode(data)

print(url)
headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}
request = urllib.request.Request(url=url, headers=headers)

response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)

3.post请求方式

import urllib.request
import urllib.parse
import json

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/103.0.0.0 Safari/537.36'
}
data = {
    'kw': 'hello'
}
# post请求的参数必须要进行编码
data = urllib.parse.urlencode(data).encode('utf-8')
# post请求的参数要放在请求对象定制的参数中

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

response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')
print(content)

# 字符串转为json对象
obj = json.loads(content)
print(obj)

post和get区别:

  1. get请求方式的参数必须编码,参数是拼接到url后面,编码之后不需要调用encode方法

  2. post请求方式的参数必须编码,参数是放在请求对象定制的方法中,编码之后需要调用encode方法

import urllib.request
import urllib.parse
import json

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

# 浏览器控制台查看header
headers = {
    'Cookie': 'BIDUPSID=3223FE11042DAD864DA852D876FDDFA9; PSTM=1654091563; BAIDUID=3223FE11042DAD86DD7C657D63E1E52C:FG=1; APPGUIDE_10_0_2=1; SOUND_PREFER_SWITCH=1; REALTIME_TRANS_SWITCH=1; HISTORY_SWITCH=1; FANYI_WORD_SWITCH=1; SOUND_SPD_SWITCH=1; BDUSS=HExR09IbHgtdi1ibEtmblo2MVdRdHdyelc5UGk3Q1MyYk1mWUZJQW9pWEtCYjlpRVFBQUFBJCQAAAAAAAAAAAEAAAABrg80x-O-~dK7ysDI4cfp2LwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMp4l2LKeJdiM; BDUSS_BFESS=HExR09IbHgtdi1ibEtmblo2MVdRdHdyelc5UGk3Q1MyYk1mWUZJQW9pWEtCYjlpRVFBQUFBJCQAAAAAAAAAAAEAAAABrg80x-O-~dK7ysDI4cfp2LwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMp4l2LKeJdiM; BDORZ=B490B5EBF6F3CD402E515D22BCDA1598; delPer=0; PSINO=1; H_PS_PSSID=36545_36722_36454_31253_36663_36413_36691_36167_36693_36698_36075_36744_26350_36685_36469; BA_HECTOR=2081850k2l24ag24011hbrb0l14; ZFY=eQSkt9DtBzoEZ2DdNJW5f:BgPs:BesKMBKOGsMVfN7H5c:C; Hm_lvt_64ecd82404c51e03dc91cb9e8c025574=1654092726,1656597526; Hm_lpvt_64ecd82404c51e03dc91cb9e8c025574=1656597526; ab_sr=1.0.1_ZjlmNzdiNWNjYTIwYTY4NTcxNGY3NDk3NjE1NGY3YmZlNTdjMjdiMzhkYjJiZWE3ZjcyOGI0NGMwNjZkYWU1YzgyMmQzMjU0ZjQ2NjBhMzI0ZTVlMDk2MjZiMjAzMDE5ZjQ2NTA0ODNlYWQ2NjEzMTk5ZWRhMmZkZTE2NWJmZDc1MDkyNDQxNTUwMzk1YjczOTdiNDUxYTJkMjlkZDA1ZmM1MzVkNWIzYjJkYWQ2Y2Q5ZmNiODk5MWZkNzBkYjUz'
}
data = {
    'from': 'en',
    'to': 'zh',
    'query': 'hello',
    'transtype': 'realtime',
    'simple_means_flag': '3',
    'sign': '54706.276099',
    'token': '406f9ef9798def66b41a2d8f61f5c96a',
    'domain': 'common'
}
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')
obj = json.loads(content)
print(obj)

# python对象转换为json字符串 ensure_ascii=False 忽略字符集编码
s = json.dumps(obj,ensure_ascii=False)
print(s)

9. ajax的get请求

简单示例:

import urllib.request

url = 'https://movie.douban.com/j/chart/top_list?type=24&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/103.0.0.0 Safari/537.36'
}

request = urllib.request.Request(url=url,headers=headers)
response = urllib.request.urlopen(request)
content = response.read().decode('utf-8')

print(content)
# 将内容保存在文件中
# open默认使用gbk编码,如果想保存汉字,指定编码格式为utf-8
# fp = open('douban.json', 'w', encoding='utf-8')
# fp.write(content)
# fp.close()

# 另一种写法
with open('douban1.json','w', encoding='utf-8') as fp:
    fp.write(content)

获取豆瓣的第一页至指定页数的数据

import urllib.request
import urllib.parse

# 创建定制请求
def create_request(page):
    url = 'https://movie.douban.com/j/chart/top_list?type=24&interval_id=100%3A90&action=&'
    # 计算当前页数据的起始和终止条数
    start = (page - 1) * 20
    limit = 20
    data = {
        'start': start,
        'limit': limit
    }
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
    }
    url += urllib.parse.urlencode(data)
    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(content, page):
    with open('douban_' + str(page) + '.json', 'w', encoding='utf-8') as fp:
        fp.write(content)
        fp.close()


# 程序的入口,写不写都可以
if __name__ == '__main__':
    start_page = 1
    end_page = int(input("请输入页数:"))

    for i in range(start_page, end_page + 1):
        request = create_request(i)
        content = get_content(request)
        down_load(content, i)

10. ajax的post请求

爬取KFC门店信息(按分页)

import urllib.request
import urllib.parse

# 定制请求
def create_request(page):
    url = 'http://www.kfc.com.cn/kfccda/ashx/GetStoreList.ashx?op=cname'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
    }
    data = {
        'cname': '北京',
        'pid': '',
        'pageIndex': page,
        'pageSize': 10,
    }
    data = urllib.parse.urlencode(data).encode('utf-8')
    request = urllib.request.Request(url=url, headers=headers, data=data)
    return request

# 获取请求内容
def get_content(request):
    response = urllib.request.urlopen(request)
    return response.read().decode('utf-8')

# 将内容写入到本地文件
def down_load(page, content):
    with open('KFC_' + str(page) + '.json', 'w', encoding='utf-8') as f:
        f.write(content)
        f.close()


if __name__ == '__main__':
    start_page = 1
    end_page = int(input('请输入页数:'))

    for i in range(start_page, end_page + 1):
        request = create_request(i)
        content = get_content(request)
        down_load(i, content)

11. URLError\HTTPError

简介:

  1. HTTPError类是URLError类的子类

  2. 导入的包urllib.error.HTTPError urllib.error.URLError

  3. http错误:http错误是针对浏览器无法连接到服务器而增加出来的错误提示。引导并告诉浏览者该页是哪里出了问题。

  4. 通过urllib发送请求的时候,有可能会发送失败,这个时候如果想让你的代码更加的健壮,可以通过try‐

except进行捕获异常,异常有两类,URLError\HTTPError

import urllib.request
import urllib.error

url = 'https://blog.csdn.net/weixin_43847283/article/details/1255564151'
# url = "http://adad121a.com"

headers = {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36'
}
try:
    request = urllib.request.Request(url=url, headers=headers)
    response = urllib.request.urlopen(request)
    print(response)
    content = response.read().decode('utf-8')
except urllib.error.HTTPError:
    print("地址错误")
except urllib.error.URLError:
    print("地址错误")

12. cookie登录

有些网站会把cookie放入header去请求,cookie存放的是登录之后的信息。请求的时候必须带上cookie才可以请求

13.Handler处理器

  • urllib.request.urlopen(url)

    • 不能定制请求头
  • urllib.request.Request(url,headers,data)

    • 可以定制请求头
  • Handler

    • 定制更高级的请求头(随着业务逻辑的复杂 请求对象的定制已经满足不了我们的需求(动态cookie和代理不能使用请求对象的定制)
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/103.0.0.0 Safari/537.36'
}
request = urllib.request.Request(url=url, headers=headers)
# 获取headler对象
handler = urllib.request.HTTPHandler()
# 获取opener对象
opener = urllib.request.build_opener(handler)
#调用open方法
response = opener.open(request)
print(response.read().decode('utf‐8'))

14. 代理服务器

  1. 代理的常用功能?

    • 突破自身IP访问限制,访问国外站点。

    • 访问一些单位或团体内部资源

      • 扩展:某大学FTP(前提是该代理地址在该资源的允许访问范围之内),使用教育网内地址段免费代理服务器,就可以用于对教育网开放的各类FTP下载上传,以及各类资料查询共享等服务。
    • 提高访问速度

      • 扩展:通常代理服务器都设置一个较大的硬盘缓冲区,当有外界的信息通过时,同时也将其保存到缓冲区中,当其他用户再访问相同的信息时, 则直接由缓冲区中取出信息,传给用户,以提高访问速度。
    • 隐藏真实IP

      • 扩展:上网者也可以通过这种方法隐藏自己的IP,免受攻击。

2.代码配置代理

  • 创建Reuqest对象

  • 创建ProxyHandler对象

  • handler对象创建opener对象

  • 使用opener.open函数发送请求

import urllib.request
import random

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/103.0.0.0 Safari/537.36'
}

request = urllib.request.Request(url=url, headers=headers)
# 定义一个代理池
proxies = [{"http": "127.0.0.1:1"}, {"http": "127.0.0.1:2"}]
# 随机取出一个代理ip
proxie = random.choice(proxies)
handler = urllib.request.ProxyHandler(proxies=proxies)
opener = urllib.request.build_opener(handler)
response = opener.open(request)
content = response.read().decode('utf‐8')
print(content)
with open('dl.html', 'w', encoding='utf‐8')as fp:
    fp.write(content)