AI编程(三十七):HTTP请求入门 — 让程序自己去网上拿东西

作者:

在

前36篇的程序再能干,也只在你自己的电脑里打转——读你硬盘上的CSV、写你硬盘上的Excel。可你想查的很多东西根本不在硬盘上:天气在气象网站上,汇率在银行网站上,新闻在新闻网站上。今天给程序接上”网线”,让它自己上网把数据拿回来。今天只引入一个新概念:requests.get()——程序版的”打开浏览器、输入网址、按回车”

一、从一个每天都要干的重复活说起

先讲个你肯定干过的事:每天早上打开浏览器,输入”沈阳天气”,看一眼,关掉。或者月底查汇率:打开银行网站,找到汇率页面,一个数字一个数字抄进表格。

一天一次不算什么,但架不住”每天”。这正是咱们从第1篇就念叨的那类活儿:固定动作、有规律、纯手工——最该交给程序的活儿。

可是前36篇的程序干不了这事。你写个程序读CSV,CSV得先在你硬盘上;你写个程序分析Excel,Excel得先下载下来。“上网查”这一步,一直是你这个”人肉搬运工”在干。

今天的任务就一句话:把这个搬运工开除,让程序自己去网上拿数据。

你可能觉得”上网”是浏览器的专利。不是。浏览器只是个”看得见的搬运工”——你在地址栏敲网址按回车,它就替你去网站上把内容搬回来,还顺便把内容画得漂漂亮亮。咱们今天学的,就是把”敲网址按回车”这个动作写成代码。至于”画得漂亮”,那是浏览器的副业,程序不需要——程序只要拿到原始内容就行。

二、今天的新概念:requests.get()——程序版的”敲网址按回车”

先花两分钟搞懂”网址”到底是什么

你在浏览器地址栏敲 https://www.weather.com.cn/weather/101010100.shtml 按回车,到底发生了什么?

把它想成寄快递就通了:

  1. https://www.weather.com.cn 是收件地址——天气网站这台”大楼”
  2. 后面那串 /weather/101010100.shtml 是门牌号——大楼里的哪个房间
  3. 按回车 = 寄出一封请求信(行话叫 HTTP 请求),信上写着”我要这个房间里的内容”
  4. 网站收到信,把网页内容打包寄回来(行话叫 HTTP 响应)

浏览器收到包裹后负责”装修”(把 HTML 画成好看的页面)。咱们的程序不需要装修,收到包裹、拆开、拿走里面的货就行。

这封”信”有自己的一套规矩,叫 HTTP(HyperText Transfer Protocol,超文本传输协议——名字唬人,其实就是”网上寄快递的规矩”)。你以后跟AI聊”HTTP”,就理解成”网上寄收快递的那套规矩”,一点都不神秘。

三行代码,一次”上网”

Python 做这件事的标准工具叫 requests(英文原意就是”请求”,名字直白到家)。先装上它:

pip install requests

然后,完整的第一次”程序上网”:

import requests

# 寄出请求信:我要这个网址的内容
回应 = requests.get("https://www.baidu.com")

# 看看包裹里有什么
print(回应.status_code)   # 网站的"回执编号":200 表示"收到了,货在信封里"
print(len(回应.text))     # 拿到的网页内容有多长(字符数)
print(回应.text[:200])    # 瞄一眼前200个字符

跑完你会看到 200,然后一大串以 开头的字符。没错,这就是百度首页的”素颜”——你在浏览器里看到的那个漂亮页面,就是浏览器拿这串字符画出来的。

就这一行 requests.get(...),顶掉了你”打开浏览器→输入网址→按回车→等待→看页面”整套手动动作。记住它今天就毕业:requests.get(网址) = “去这个网址把内容拿回来”。

三个最常用的”拆包裹”动作

拿回来的 回应 对象里,最常用的就是这三样(今天先把这三样用熟,够用了):

写法 意思 什么时候用

|——|——|———–|

回应.status_code 网站的回执编号 先看它,判断”货到没到”
回应.text 网页的文字内容 要”读内容”的时候
回应.ok 是不是”好收据”(True/False) 懒得记编号时的快捷判断

status_code 那个数字是网站给你的回执,最常见的是这几种:

  • 200——”收到了,货在信封里”(一切正常)
  • 404——”查无此人”(网址写错了,或者页面被删了)
  • 403——”不接待”(网站拒绝你进入)
  • 500——”我们这边仓库塌了”(网站自己出故障了)

疫苗先打一针:requests.get() 成功执行 ≠ 拿到了数据。它只保证”信寄出去了、有回音”,回音可能是”404 查无此人”。所以拿到回应先看 status_code,就像收快递先看”拒收退回”还是”签收成功”。

把”查天气”改成程序版(先看个雏形)

下面是完整可运行的雏形,用一个专门给程序员练手的网站(httpbin.org,收到什么请求就原样回给你什么,特别适合当”沙袋”):

import requests

def 拿网页内容(网址):
    """去指定网址把内容拿回来。拿不到就返回 None。"""
    回应 = requests.get(网址, timeout=10)   # timeout=10:最多等10秒,别傻等
    if 回应.status_code == 200:
        return 回应.text
    else:
        print(f"出师不利,网站回执编号:{回应.status_code}")
        return None

内容 = 拿网页内容("https://httpbin.org/get")
if 内容:
    print("拿到了!内容开头是:")
    print(内容[:300])

注意两处细节,都是上过战场的人才会写上的:

  1. timeout=10——不写它,如果网站卡住不回信,你的程序会无限期傻等,像打客服电话永远不挂断
  2. 先检查状态码再用内容——”货到没到”和”货好不好”是两码事

网址里的问号:同一个网站,查不同的东西

看这两条网址,眼熟吗?

https://www.weather.com.cn/weather/101010100.shtml   ← 北京天气
https://www.weather.com.cn/weather/101070101.shtml   ← 沈阳天气

页面结构一模一样,只有结尾那串数字不同——网址本身就能”带问题”。还有一种更明显的写法,问号后面挂一串”参数”:

https://www.baidu.com/s?wd=python教程

问号 ? 后面的 wd=python教程 就是”我问的问题”:wd 是参数名(要搜什么),等号后面是参数值。同一个网站,换参数就换内容——这就是”查天气”能自动换城市、”查汇率”能自动换币种的秘密。

在 requests.get 里,你不用手工拼这串问号,把参数装进字典递给 params 就行(字典,第13篇的老朋友):

import requests

# 同一个网址模板,换参数换内容——httpbin 会把参数原样回显,特别适合练手
参数 = {"city": "沈阳", "days": "3"}
回应 = requests.get("https://httpbin.org/get", params=参数, timeout=10)

print(回应.status_code)
print(回应.text[:300])   # 看看它回显的 "args" 里是不是你传的两个参数

跑完你会发现回显里出现了 "city": "沈阳"——你问的问题,网站收到了。今天先到”会带参数提问”为止,怎么从回应里把答案精准抠出来(JSON 格式),下一篇的主角就是它。

三、跟AI说需求→读懂→改进:第一次”网络版”三步走

老规矩,这一节是本系列的保留节目。今天用它来做一个真实的小工具:查一个网页能不能正常打开(网站值守的迷你版)。

第一步:跟AI说需求

“我是编程初学者,正在学 requests.get()。帮我写个Python函数:输入一个网址,程序去访问它,如果回执是200就说’网页正常’,否则把回执编号打印出来。代码要完整可运行,加中文注释。”

AI大概率给你这样的代码:

import requests

def 检查网页(网址):
    回应 = requests.get(网址, timeout=10)
    if 回应.status_code == 200:
        print(f"{网址} 网页正常")
    else:
        print(f"{网址} 出问题了,回执编号:{回应.status_code}")

检查网页("https://www.baidu.com")

第二步:读懂(逐行对照)

  • def 检查网页(网址)——函数,第7篇的老朋友,输入网址输出检查结果
  • requests.get(网址, timeout=10)——今天的新概念,寄信+最多等10秒
  • if 回应.status_code == 200——回执检查,第4篇的条件判断
  • f字符串打印——第2篇就会了

没有一个语法是你不认识的,唯一的”新面孔”只有 requests.get()。这就是”每篇只引入一个新概念”的好处。

第三步:改进(这是拉开差距的一步)

拿AI的代码直接跑,会发现两个问题,正好当今天的”坑点疫苗”:

坑1:网址根本打不开时,程序直接崩给你看。比如你断网了,或者把网址打成 htp://...,程序会抛出一大段红字 ConnectionError。在咱们的”跟AI说需求”哲学里,这叫”没按剧本演”——正常路径好好的,一出意外就崩。

改进的话这么说:

“断网或网址写错时程序会抛异常崩溃。请用 try/except 包起来,出错时打印’访问失败’和原因,不要让程序崩。”

坑2:只检查一次,看不出”是不是一直都正常”。网站偶尔抽风一下和真的挂了,是两回事。

改进的话:

“帮我加一个循环,同一个网址连续检查3次,每次间隔5秒,最后报告成功了几次。”

合起来的成品(完整可运行):

import requests
import time

def 检查网页(网址, 次数=3, 间隔秒=5):
    """连续检查一个网址几次,报告成功了几次。"""
    成功次数 = 0
    for 第几次 in range(1, 次数 + 1):
        try:
            回应 = requests.get(网址, timeout=10)
            if 回应.status_code == 200:
                print(f"第{第几次}次:正常")
                成功次数 += 1
            else:
                print(f"第{第几次}次:回执编号 {回应.status_code}")
        except requests.RequestException as 原因:
            # 断网、网址写错、超时……全都归这里管
            print(f"第{第几次}次:访问失败({原因})")
        if 第几次 < 次数:
            time.sleep(间隔秒)   # 歇口气再查,别把人家网站查烦了
    print(f"总共 {成功次数}/{次数} 次正常")

检查网页("https://www.baidu.com")

这个改进版多了一样今天没细讲的东西:try/except(异常处理)。不用慌,它的意思就一句话:”这块代码要是出岔子,别崩溃,跳到 except 这儿来,按我说的办。“具体细节后面有专门的课讲,今天照猫画虎能跑就行。

四、四个必踩的坑(先打疫苗)

坑1:装了库却说找不到。 ModuleNotFoundError: No module named 'requests'——十有八九是”你装的 Python”和”你跑代码的 Python”不是同一个。在终端里敲 pip install requests 装到了A处,结果编辑器用的是B处的 Python。疫苗:报错就改用 python -m pip install requests,指定用”跑代码的那个 Python”自己去装。

坑2:拿了回执就当拿到了货。 上面说过,requests.get() 不抛异常只说明”有回音”,404 也是回音。先看 status_code,再用 text,这个顺序错不得。

坑3:不写 timeout,程序假死。 网站不回信时,不写 timeout 的程序会永远等下去,你以为它在干活,其实它在发呆。疫苗:requests.get 永远带上 timeout=10,这是写给”未来倒霉的自己”的保险。

坑4:拿别人网站当自家后院。 写个循环每秒查人家网站100次,轻则被封IP,重则给对方服务器添堵——这是不地道的。疫苗:循环访问记得 time.sleep() 间隔几秒,正式爬数据之前看看人家网站的规矩(后面第47篇专门讲”爬虫礼仪”)。

另外提前说个小坑:拿到的 回应.text 里如果中文显示成乱码,多半是网站没说清自己用什么编码。第41篇爬虫实战时会专门收拾它,今天先认识一下”乱码了不是你的错”。

五、跟AI协作的正确姿势(网络版特供)

写网络代码,AI的盲区格外明显:它没在你现在的网络环境里跑过代码,所以它写的代码”理论上对”,但”你的网络、你要访问的网站”它一无所知。三条特供建议:

  1. 把真实网址给AI。别问”怎么请求一个网站”,要问”帮我 requests.get 这个网址 https://xxx.com/yyy,把里面的XXX提取出来”。网址越具体,代码越能直接用。
  2. 把完整报错贴回去。网络代码的报错最有信息量(ConnectionError、Timeout、SSLError……),原样贴给AI,它基本能一眼定位。别自己转述”它崩了”。
  3. 让AI写”防崩版”。直接说”请加 try/except 和 timeout,出错不要崩,打印友好提示”。网络代码天生比本地代码脆弱——你管得住自己的代码,管不住人家的网站。

六、今日小练习

练习1:程序版”网址体检”。写一个函数,输入网址,输出”能打开(200)”或”打不开,回执编号是XXX”。

提示:requests.get(网址, timeout=10) 拿回执,if 回应.status_code == 200 分两路。试着分别拿 https://www.baidu.com 和一个故意写错的网址跑一跑,看看两种回执长什么样。

练习2:给函数加上”断网保护”。把练习1的函数用 try/except 包一层,断网时(可以试试把网址写成 htp://www.baidu.com 模拟敲错)程序不崩溃,打印”访问失败”。

提示:except requests.RequestException as 原因: 能接住所有网络故障,打印 原因 就能看到具体是哪种。

练习3(动脑题):想想你会拿它干什么。列三个”每天都要上网看一眼”的东西(天气、汇率、快递状态、油价、某个页面更新没……),挑一个最想要的,写下:①它的网址大概是什么 ②你想从页面上拿走哪个信息。

提示:这题不用写代码——但请认真做,因为下篇预告里,我们就要真的做第一个了。你现在写下的需求,就是下节课的”跟AI说需求”素材。

下篇预告

下一篇(第38篇):API调用 —— 网站的”官方点餐窗口”。今天你从网页上”看”数据,可网页是画给人看的,从里面抠数据又费劲又容易碎。很多网站其实留了个”官方窗口”(API):你递上一句正经请求,它直接把干干净净的数据(JSON)端给你——天气、汇率这类活儿,用API三行代码就能搞定。下一篇,咱们把”查天气”这件事做成真家伙。

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注