urllib.request.Request
import urllib.request
import urllib.parse
url = 'https://www.runoob.com/?s=' # 菜鸟教程搜索页面
keyword = 'Python 教程'
key_code = urllib.request.quote(keyword) # 对请求进行编码
url_all = url+key_code
header = {
'User-Agent':'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'
} #头部信息
request = urllib.request.Request(url_all,headers=header)
reponse = urllib.request.urlopen(request).read()
fh = open("./urllib_test_runoob_search.html","wb") # 将文件写入到当前目录中
fh.write(reponse)
fh.close()
代码的整体目标
这段代码的目的是模拟一个用户在“菜鸟教程”网站的搜索框中输入“Python 教程”,然后将返回的搜索结果页面完整地保存为一个HTML文件。
代码原理分步解析
我们可以将代码拆解为几个关键步骤来理解其工作原理和目的。
第一步:导入必要的库
import urllib.request
import urllib.parse
-
代码原理:
urllib.request
: 这是Python中用于处理URL请求的核心模块。它能让你像打开本地文件一样打开和读取一个网页,是进行网络爬虫的基础。urllib.parse
: 这个模块用于解析URL。在这个例子中,虽然代码里写的是urllib.request.quote
,但quote
函数实际上主要在urllib.parse
模块中,它的功能是进行URL编码。
-
为什么要这么做:
- 程序需要网络通信和URL处理功能,这些功能不是Python默认就加载的,必须通过
import
语句显式地导入进来才能使用。
- 程序需要网络通信和URL处理功能,这些功能不是Python默认就加载的,必须通过
第二步:定义目标和参数
url = 'https://www.runoob.com/?s=' # 菜鸟教程搜索页面
keyword = 'Python 教程'
-
代码原理:
url
: 定义了目标网站的搜索接口地址。通常,网站的搜索功能是通过URL参数来实现的,这里的?s=
就是一个查询参数,s
代表"search"(搜索),等号后面就是要搜索的内容。keyword
: 定义了我们想要搜索的关键词。
-
为什么要这么做:
- 将URL和关键词分开定义,可以让代码更清晰、更易于维护。如果你想搜索其他内容,只需要修改
keyword
变量的值,而不用改动其他代码。
- 将URL和关键词分开定义,可以让代码更清晰、更易于维护。如果你想搜索其他内容,只需要修改
第三步:对关键词进行URL编码
key_code = urllib.request.quote(keyword) # 对请求进行编码
url_all = url+key_code
-
代码原理:
urllib.request.quote(keyword)
: 这是非常关键的一步。URL只能包含标准的ASCII字符。当你的请求参数包含中文、空格或其他特殊字符时,必须将它们转换成一种URL认可的格式,这个过程就叫URL编码或百分号编码。例如,Python 教程
会被编码成Python%20%E6%95%99%E7%A8%8B
。url_all = url+key_code
: 将基础URL和编码后的关键词拼接起来,形成一个完整、合法的请求URL。
-
为什么要这么做:
- 直接原因:如果不进行编码,直接把含有中文的URL(
https://www.runoob.com/?s=Python 教程
)发送出去,服务器很可能无法正确识别,导致请求失败或返回错误的结果。 - 根本原因:这是由URL的标准规范决定的,它保证了URL在任何地方都能被正确地解析和传输。
- 直接原因:如果不进行编码,直接把含有中文的URL(
第四步:伪装成浏览器
header = {'User-Agent':'Mozilla/5.0 (X11; Fedora; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'
}
request = urllib.request.Request(url_all,headers=header)
-
代码原理:
header
: 创建一个字典,其中包含一个User-Agent
字段。User-Agent
是HTTP请求头(Header)的一部分,它会告诉服务器发起请求的客户端是什么(比如是什么浏览器、什么操作系统)。urllib.request.Request()
: 创建一个Request
对象。与直接将URL字符串传给urlopen
相比,创建一个Request
对象可以让我们更灵活地定制请求,比如添加请求头。
-
为什么要这么做:
- 反爬虫策略:很多网站为了防止被爬虫程序恶意抓取,会检查请求的
User-Agent
。Python的urllib
库默认的User-Agent
是Python-urllib/3.x
,服务器一看到这个就知道是程序在访问,很可能会拒绝服务。 - 模拟真实用户:通过将
User-Agent
设置成一个真实浏览器的信息(比如这段代码中的Chrome浏览器),我们的程序就能“伪装”成一个正常的浏览器在访问网站,从而大大提高请求成功的概率。
- 反爬虫策略:很多网站为了防止被爬虫程序恶意抓取,会检查请求的
第五步:发送请求并获取响应
reponse = urllib.request.urlopen(request).read()
-
代码原理:
urllib.request.urlopen(request)
: 将我们构建好的、带有伪装头信息的Request
对象发送给服务器。服务器接收到请求后,会返回一个响应对象。.read()
: 读取响应对象中的所有内容。对于一个网页请求,这里读取到的就是整个页面的HTML源代码。返回的内容是**字节(bytes)**类型。
-
为什么要这么做:
- 这是与服务器进行实际交互并获取数据的核心步骤。我们前面所有的准备工作(构建URL、伪装头部)都是为了让这一步能成功执行。
urllib.request.urlopen() 函数有两种主要的用法:
- 简单用法:直接传入URL字符串
这是最基础的用法,当你只需要简单地访问一个网址,不需要任何额外的设置时,就可以这么做。
code
import urllib.requesturl = 'http://www.example.com'
response = urllib.request.urlopen(url) # 直接传入字符串
print(response.read().decode('utf-8'))
```
在这种情况下,Python会在背后为你默默地创建一个默认的Request对象,然后发送出去。这个默认请求不包含任何特殊的头部信息(比如User-Agent)。
2. 高级用法:传入一个Request对象
当你需要对你的请求进行更多的定制时,比如添加头部信息(Headers)、发送POST数据等,你就不能只传一个简单的URL字符串了。
这时,你需要先创建一个urllib.request.Request类的实例(对象),把所有你想要定制的信息都“打包”到这个对象里,然后再把这个完整的Request对象传给urlopen()函数。#### **第六步:将结果保存到文件**```python
fh = open("./urllib_test_runoob_search.html","wb")
fh.write(reponse)
fh.close()
```* **代码原理**:* `open("./urllib_test_runoob_search.html", "wb")`: 打开(或创建)一个名为`urllib_test_runoob_search.html`的文件。关键在于模式`"wb"`:* `w`: 代表写入(write)模式。如果文件已存在,会覆盖旧内容。* `b`: 代表二进制(binary)模式。* `fh.write(reponse)`: 将我们从网上获取到的字节内容写入这个文件中。* `fh.close()`: 关闭文件,释放资源。* **为什么要这么做**:* **使用`"wb"`(二进制写入)**:因为上一步`reponse = ... .read()`获取到的是字节(bytes)类型的数据,而不是字符串(string)。处理网络数据流时,最安全的方式就是用二进制模式进行读写,这样可以确保数据内容不会因为编码问题而出错。如果用`"w"`(文本模式),在写入字节时会引发`TypeError`。* **保存结果**:将抓取到的HTML保存下来,方便我们后续用浏览器打开查看,验证抓取结果是否正确,或者用其他程序(如BeautifulSoup)来进一步解析和提取数据。### **总结**这段代码是一个非常基础和完整的网络爬虫流程:1. **确定目标** (搜索“Python 教程”)。
2. **构建请求** (编码关键词,拼接URL)。
3. **伪装自己** (添加`User-Agent`头,避免被反爬)。
4. **发送请求** (与服务器通信)。
5. **接收并保存数据** (将返回的HTML存为本地文件)。每一步都有其明确的目的,共同构成了一次成功的网络数据抓取任务。