别让你的爬虫“裸奔”出门!urllib.request的‘易容术’大揭秘
嘿,各位爬虫萌新们,有没有遇到过这种尴尬情况?你摩拳擦掌,写了几行代码,感觉即将成为数据江湖的侠客,结果一运行——HTTP Error 403: Forbidden?或者返回一堆乱码,甚至直接给你跳转到一个验证页面?
别慌,别怀疑人生,这大概率不是你的代码写错了,而是你的爬虫……它正在“裸奔”!
啥是“裸奔”? 就是你啥也没打扮,直接让urllib.request.urlopen()就冲出去了。在服务器看来,你这模样实在是太可疑了:一个没有User-Agent(用户代理)、没有Accept(接受内容类型)、没有任何“社会身份”的访问,不是脚本机器人是啥?不拦你拦谁?
今天,咱就来给咱们的爬虫兄弟好好上一堂“形象管理课”,教它如何用urllib.request模块,进行完美的“易容”,从人见人打的“脚本小弟”,伪装成彬彬有礼的“浏览器先生”。
第一幕:为啥要“易容”?Header到底是啥玩意儿?
想象一下这个场景:你走进一家高档餐厅(目标网站)。
- “裸奔”的爬虫就像你穿着背心、裤衩、人字拖就进去了。服务员(服务器)一看,眉头紧锁:“这位客人,我们这儿有着装要求(反爬虫机制),请您离开(返回403错误)。”
- 而伪装好的爬虫,则是西装革履,头发梳得一丝不苟。你一进门就微笑着说:“你好,我是一位用Chrome浏览器的普通用户,想看看你们的菜单(网页数据)。” 服务员一看,哎,正常客人,里面请!
这里你说的那句“自我介绍”,就是HTTP Header。它是HTTP协议里,客户端发给服务器的一串“附加信息”,用来告诉服务器这次请求的详细信息。
几个关键的“易容”道具(Header字段):
- User-Agent(用户代理):这是最重要的! 它告诉服务器你用的什么浏览器、什么操作系统。不带这个,就等于在喊“我不是人!”
- Referer:你是从哪个页面跳转过来的。有时候服务器会检查这个,防止你“空降”。
- *Accept-系列:告诉服务器你的客户端能接受什么类型的内容(文本、图片、JSON等)。
- Cookie:维持登录状态的神器,今天先不深入,但它非常重要。
urllib.request给了我们一个超级工具来携带这些信息,它就是——Request对象。
第二幕:快速换装——使用Request对象
别再直接用urlopen(‘网址’)了!太原始了!我们要学会先“包装”请求。
基础版易容术:带上User-Agent
看代码,这是最核心的一步:
import urllib.request
import urllib.parse
# 目标网址(我们找个测试用的网站)
url = 'http://httpbin.org/user-agent' # 这个网站会把你发送的User-Agent原样返回
# 1. 定义一个看起来像真实浏览器的Headers字典
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36'
}
# 2. 创建Request对象,并把网址和headers丢进去
request = urllib.request.Request(url, headers=headers)
# 3. 用urlopen发送这个已经“包装”好的请求
response = urllib.request.urlopen(request)
# 4. 读取响应内容
html = response.read().decode('utf-8')
print(html)
运行结果,你会看到类似:
{
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"
}
看!服务器收到的,不再是什么Python-urllib/3.9,而是一个正经的Chrome浏览器标识!你的爬虫已经成功穿上了“西装”!
Request对象就像是一个快递订单,urlopen只是负责派送。你在订单上写清楚了寄件人信息(Headers),快递员(urlopen)就会照单全送。
第三幕:精装修——动态添加与修改Header
有时候,我们创建Request对象时,可能忘了加某个Header,或者中途想改一下。怎么办?Request对象自带了一个叫 add_header() 的方法。
import urllib.request
url = 'http://httpbin.org/headers'
# 先创建一个Request对象,只带User-Agent
request = urllib.request.Request(url)
request.add_header('User-Agent', 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.1.1 Safari/605.1.15')
# 中途觉得,哎,我得告诉服务器我能接受json格式,再加一个!
request.add_header('Accept', 'application/json')
# 发送请求
response = urllib.request.urlopen(request)
print(response.read().decode('utf-8'))
这个方法非常灵活,就像是在出门前,又往西装口袋里塞了张名片(Accept头),让形象更完美。
第四幕:终极奥义——创建“全球形象顾问”(Opener和Handler)
上面的方法,一次请求包装一次,挺好。但如果你的爬虫需要像007一样,执行一系列连续任务(发送多个请求),每次都手动Request再urlopen,是不是有点麻烦?
这时候,你需要一个“全球形象顾问”——OpenerDirector(通常简称opener)。这个顾问会记住你的所有形象设定,并自动应用到你的每一次行动(请求)中。
怎么打造这个顾问?我们需要用到**HTTPHandler和build_opener**。
import urllib.request
# 定义一个强大的Headers,全方位伪装
headers = {
'User-Agent': 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2',
'Connection': 'keep-alive',
'Upgrade-Insecure-Requests': '1',
}
# 1. 创建一个处理器(Handler),你可以理解为顾问的“大脑”
# 默认情况下,它什么也不做,但我们可以在创建时注入“人格”(headers)
opener = urllib.request.build_opener()
# 2. 把我们的headers以(键,值)对的形式,批量添加到opener中
opener.addheaders = list(headers.items())
# 3. 安装这个opener,让它成为全局默认的“顾问”。
# 从此以后,哪怕你用最简单的`urlopen(url)`,也会自动使用这个伪装好的opener!
urllib.request.install_opener(opener)
# 测试一下:现在直接用urlopen,看看是不是已经伪装好了?
response = urllib.request.urlopen('http://httpbin.org/user-agent')
print("使用全局Opener的结果:")
print(response.read().decode('utf-8'))
# 你也可以不安装为全局,而是单独使用这个opener
# response = opener.open('http://httpbin.org/headers')
# print(response.read().decode('utf-8'))
这种方法堪称“一劳永逸”。一旦设置好,你的整个脚本里的所有urllib.request请求,都会自动带上这全套Header,省心省力!
第五幕:完整实战——挑战一个“看脸”的网站
光说不练假把式,我们来个完整的例子。假设我们要抓取一个对Header有基本检查的网站(比如一些简单的新闻门户)。
import urllib.request
import urllib.error
def sophisticated_spider(url):
"""
一个穿着得体的爬虫函数
"""
# 精心准备的Header
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36 Edg/91.0.864.59',
'Accept-Language': 'zh-CN,zh;q=0.9,en;q=0.8',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Connection': 'keep-alive'
}
try:
# 包装请求
request = urllib.request.Request(url, headers=headers)
# 发送请求并获取响应
response = urllib.request.urlopen(request)
# 判断请求是否成功(HTTP状态码为200)
if response.status == 200:
data = response.read()
# 解码。有些网站可能是gbk编码,需要灵活处理
try:
html = data.decode('utf-8')
except UnicodeDecodeError:
html = data.decode('gbk')
# 这里通常会用BeautifulSoup等库来解析html,提取数据
# 我们今天就简单打印一下标题标签证明成功了
if '<title>' in html:
title_start = html.find('<title>') + 7
title_end = html.find('</title>', title_start)
print(f"页面标题:{html[title_start:title_end]}")
else:
print("成功获取页面内容,但未找到标题。")
# 你可以将html保存到文件,或进行后续解析
# with open('page.html', 'w', encoding='utf-8') as f:
# f.write(html)
else:
print(f"请求失败,状态码:{response.status}")
except urllib.error.HTTPError as e:
print(f"HTTP错误:{e.code} - {e.reason}")
except urllib.error.URLError as e:
print(f"URL错误:{e.reason}")
except Exception as e:
print(f"发生未知错误:{e}")
# 使用示例 (请替换成一个真实的、对Header不严苛的网站进行测试,避免给别人造成压力)
if __name__ == '__main__':
target_url = 'https://httpbin.org/html' # 一个返回示例HTML页面的网址
print("爬虫开始工作...")
sophisticated_spider(target_url)
print("任务完成!")
尾声:易容师的自我修养(注意事项)
- User-Agent库:别总用一个User-Agent,可以准备一个列表,随机选一个用,降低被封风险。
- 适度原则:伪装是为了友好地获取公开数据,别去疯狂请求把人家的服务器搞垮了,那不道德,也可能违法。
- 进阶挑战:修改Header只是反爬虫的第一道门槛。后面还有Cookie、验证码、IP封锁、JavaScript渲染等大山等着你。那时候,你可能需要请出
requests、Selenium、Scrapy这些更专业的“特工工具包”。 - 编码问题:解码时(
decode),如果utf-8报错,试试gbk或gb2312,特别是国内的一些老网站。
好了,恭喜你!你的爬虫已经成功毕业,从“裸奔菜鸟”晋级为“初级易容师”了。记住,在数据的江湖里,有时候“以貌取人”是通行法则。穿上合适的“衣服”,你的爬虫之路会顺畅很多!
现在,就去给你的代码“换装”吧!

被折叠的 条评论
为什么被折叠?



