Python从入门到精通day60

用Python获取网络数据

网络数据采集是Python语言极具优势的应用领域,上节课我们提到过,实现自动化网络数据采集的程序,通常被称作网络爬虫或蜘蛛程序。即便身处大数据时代,数据获取依旧是绝大多数中小企业的短板,部分数据可以通过开放接口或是付费接口获取,而大量行业数据、竞品数据,依旧需要通过网络数据采集的方式来获取。无论选用哪种方式获取网络数据,Python都是十分优质的选择,得益于完善的标准库与丰富的第三方库,Python对网络数据采集全流程都提供了全面且便捷的支持。

requests库

使用Python实现网络数据获取,首选第三方库为requests,该库在之前的课程中我们已经有过基础使用。根据官方定义,requests基于Python内置标准库深度封装,极大简化了HTTP、HTTPS协议下的网络资源访问操作。上节课我们讲到,HTTP是典型的请求-响应式协议,在浏览器中输入正确的URL(统一资源定位符,也就是日常所说的网址)并按下回车键,就会向对应Web服务器发送一条HTTP请求,服务器接收并处理请求后,会返回对应的HTTP响应。在Chrome浏览器中,通过菜单栏打开开发者工具,切换至Network选项卡,即可直观查看完整的HTTP请求与响应报文,效果如下图所示。

借助requests库,Python程序可以模拟浏览器行为,向Web服务器发起网络请求、接收服务器返回的响应数据,进而从响应结果中提取目标信息。我们日常浏览的网页,均由HTML超文本标记语言编写而成,浏览器相当于HTML的解析渲染环境,页面内所有展示内容,都嵌套在各类HTML标签之中。获取到完整的HTML源码后,就能从标签属性或者标签文本中提取所需数据。下方代码示例,演示了通过requests库的get方法,获取搜狐首页HTML源码的完整流程。

复制代码
import requests

resp = requests.get('https://www.sohu.com/')
if resp.status_code == 200:
    print(resp.text)

说明 :上面代码中的变量resp是一个Response对象,由requests库封装而成。通过该对象的status_code属性可以获取服务器返回的响应状态码,以此判断请求是否成功;而该对象的text属性,可以直接获取页面解析后的HTML文本代码。

Response对象的text属性返回值为字符串格式,我们可以结合之前学习的正则表达式知识,从页面HTML源码中提取新闻标题、链接等目标信息,具体实现代码如下所示。

复制代码
import re

import requests

pattern = re.compile(r'<a.*?href="(.*?)".*?title="(.*?)".*?>')
resp = requests.get('https://www.sohu.com/')
if resp.status_code == 200:
    all_matches = pattern.findall(resp.text)
    for href, title in all_matches:
        print(href)
        print(title)

除了文本类网页数据,requests库也可以通过URL,直接获取图片、音频等二进制资源。下方示例演示了获取百度Logo图片,并将其保存为本地baidu.png文件的操作,大家可以在百度首页右键点击Logo,选择"复制图片地址"菜单项,即可获取对应的图片URL。

复制代码
import requests

resp = requests.get('https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png')
with open('baidu.png', 'wb') as file:
    file.write(resp.content)

说明Response对象的content属性,可以获取服务器返回的二进制响应数据,专门用于处理图片、文件等非文本类资源。

requests库使用便捷、功能全面,后续我们会结合实操场景,逐步剖析它的核心用法。如果想学习requests库的更多知识点,可以查阅它的官方文档,系统掌握各项用法。

编写爬虫代码

接下来我们以豆瓣电影平台为例,实操讲解基础爬虫代码的编写逻辑。沿用前面讲解的方法,先通过requests库获取页面HTML源码,将完整源码看作一个长字符串,再利用正则表达式的捕获组,精准提取所需内容。下方代码实现了从豆瓣电影Top250页面,获取上榜电影信息的功能,豆瓣电影Top250的页面结构与对应源码如下图所示。

可以看到,豆瓣电影Top250页面,单页展示25部电影,想要获取全部250条数据,需要遍历访问10个页面,对应请求地址格式为https://movie.douban.com/top250?start=xxx,这里的xxx为数据起始位置参数,参数为0时对应第一页,参数为100时对应第五页。为了让代码简洁易懂,本次实操只提取电影标题和评分两项核心数据。

复制代码
import random
import re
import time

import requests

for page inrange(1, 11):
    resp = requests.get(
        url=f'https://movie.douban.com/top250?start={(page - 1) * 25}',
        # 如果不设置HTTP请求头中的User-Agent,豆瓣会检测出非浏览器访问,直接拦截请求
        # 通过get函数的headers参数设置User-Agent,参数值可在浏览器开发者工具中查看
        # 爬虫访问大部分网站时,伪装成浏览器请求都是规避反爬的关键步骤
        headers={'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36'}
    )
    # 通过正则表达式,匹配class为title、且内容不含&的span标签,提取电影标题
    pattern1 = re.compile(r'<span class="title">([^&]*?)</span>')
    titles = pattern1.findall(resp.text)
    # 通过正则表达式,匹配class为rating_num的span标签,提取电影评分
    pattern2 = re.compile(r'<span class="rating_num".*?>(.*?)</span>')
    ranks = pattern2.findall(resp.text)
    # 使用zip合并两个列表,循环遍历输出电影标题与对应评分
    for title, rank inzip(titles, ranks):
        print(title, rank)
    # 随机休眠1-5秒,控制请求频率,避免频繁请求触发网站反爬机制
    time.sleep(random.random() * 4 + 1)

说明 :分析豆瓣网的robots协议可知,豆瓣并不拒绝百度爬虫抓取站内公开数据,因此也可以将爬虫伪装成百度爬虫,将get函数的headers参数简化修改为:headers={'User-Agent': 'BaiduSpider'}

使用 IP 代理

编写爬虫程序时,隐匿真实请求身份是核心环节。大部分网站对大规模爬虫请求都较为抵触,因为爬虫会消耗大量服务器带宽,产生大量无效流量,甚至影响正常用户访问。想要彻底隐匿爬虫真实身份,通常需要使用商业IP代理(如蘑菇代理、芝麻代理、快代理等),让被爬取网站无法获取爬虫的真实IP地址,也就无法通过IP封禁的方式拦截爬虫。

下面以蘑菇代理为例,为大家讲解商业IP代理的实操使用方法。首先需要在该平台注册账号,注册完成后购买对应套餐,即可获取IP代理使用权限。如果是商业爬虫使用,建议选购不限量套餐,能根据实际需求获取充足的代理IP;如果是学习测试使用,可以选购包时套餐,或是根据自身需求灵活选择。蘑菇代理提供两种接入方式,分别是API私密代理和HTTP隧道代理,前者通过请求官方API接口获取代理服务器地址,后者直接使用统一入口域名接入,操作更简便。

接下来以HTTP隧道代理为例,讲解IP代理的接入方式,大家也可以直接参考蘑菇代理官网提供的示例代码,适配自己的爬虫项目。

复制代码
import requests

# 替换为个人代理订单对应的AppKey
APP_KEY = 'Wnp******************************XFx'
PROXY_HOST = 'secondtransfer.moguproxy.com:9001'

for page inrange(1, 11):
    resp = requests.get(
        url=f'https://movie.douban.com/top250?start={(page - 1) * 25}',
        # 请求头中配置代理认证信息与浏览器伪装
        headers={
            'Proxy-Authorization': f'Basic {APP_KEY}',
            'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.159 Safari/537.36',
            'Accept-Language': 'zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4'
        },
        # 配置HTTP与HTTPS代理服务器
        proxies={
            'http': f'http://{PROXY_HOST}',
            'https': f'https://{PROXY_HOST}'
        },
        verify=False
    )
    # 提取电影标题与评分数据
    pattern1 = re.compile(r'<span class="title">([^&]*?)</span>')
    titles = pattern1.findall(resp.text)
    pattern2 = re.compile(r'<span class="rating_num".*?>(.*?)</span>')
    ranks = pattern2.findall(resp.text)
    for title, rank inzip(titles, ranks):
        print(title, rank)

说明 :使用上述代码时,需要将APP_KEY替换为个人代理订单对应的AppKey,该参数可在平台用户中心的订单列表中查看。蘑菇代理提供免费的API代理与HTTP隧道代理试用,但试用版代理接通率无法保证,学习测试建议选购性价比合适的正规代理套餐体验。

总结

Python语言的应用场景十分广泛,单论网络数据采集这一领域,Python几乎占据绝对优势,大量企业和开发者都使用Python从互联网上获取所需数据,这也会成为大家日后日常开发工作的常用技能。

另外,虽然正则表达式可以实现网页数据提取,但编写一套精准、适配需求的正则表达式难度并不小,对于新手来说尤为明显。下一节课,我们会讲解另外两种网页数据提取方法,这类方法虽说性能略逊于正则表达式,但大幅降低了编码复杂度,上手更轻松,相信大家学习后会十分受用。

相关推荐
不知名的老吴2 小时前
返回多个值:让函数输出更丰富又不复杂
开发语言·python
larance2 小时前
python包 解压修改后重新打成whl 包
开发语言·python
551只玄猫2 小时前
【数学建模 matlab 实验报告7】微分方程和差分方程
开发语言·数学建模·matlab·课程设计·实验报告
萤火阳光2 小时前
43|Python 异步生态深度:aiohttp/aiomysql/aioredis 全链路异步实战
开发语言·网络·python
妖萌妹儿2 小时前
postman怎么做参数化批量测试,测试不同输入组合
开发语言·javascript·postman
酉鬼女又兒2 小时前
零基础快速入门前端ES6 核心特性详解与蓝桥杯 Web 考点实践(可用于备赛蓝桥杯Web应用开发)
开发语言·前端·职场和发展·蓝桥杯·es6·css3·html5
威联通安全存储2 小时前
云原生数据湖:QuObjects 本地 S3 对象存储解析
python·云原生
计算机安禾2 小时前
【数据结构与算法】第23篇:树、森林与二叉树的转换
c语言·开发语言·数据结构·c++·线性代数·算法·矩阵
chushiyunen2 小时前
大模型评测、质量保证、datasets数据集、LmEval工具
开发语言·python