初识网络爬虫(二)

网络请求urllib模块

了解urllib

python2中有urllib和urllib2两种模块,urllib只能接收一个URL不能伪装用户代理等字符串操作。urllib2可以接收一个Request对象,并通过这样的方法来设置一个URL的Headers;
python3中将urllib和urllib2 功能组合为了urllib模块(合体版)
python3中urllib的子模块具体内容如下:

urllib.request :用于实现基本的HTTP请求的模块。
urllib.error :异常处理模块,如果在发送网络请求时出现了错误,可以捕获的有效处理。
urllib.parse :用于解析URL的模块
urllib.robotparser :用于解析robots.txt文件,判断网站是否可以爬取信息

发送网络请求

urllib.request模块提供了urlopen()方法,用于实现最基本的HTTP请求,然后接收服务器返回的响应数据。urlopen()方法的语法格式如下:

urllib.request.urlopen(url,data=None,[timeout,]*,cafile=None,capath=None,cadefault=False,context=None)

#参数说明
url : 需要访问网站的URL完整地址。
data : 该参数默认为None,通过该参数确认请求方式,如果是None,表示请求方式为GET,
否则请求方式为POST。在发送POST请求时,参数data需要以字典形式的数据作为参数值,
并且需要将字典类型的参数值转化为字节类型的数据才可以实现POST请求。
timeout : 以秒为单位,设置超时。
cafile、capath : 指定一组HTTPS请求信任的CA证书,cafile指定包含CA证书的单个文件,
capath指定证书文件的目录。
cadefault : CA证书默认值
context : 描述SSL选项的实例

发送GET请求

在使用urlopen()方法实现一个网络请求时,所返回的是一个“http.client.HTTPResponse”对象。示例代码如下

import urllib.request
response = urllib.request.urlopen('https://www.baidu.com')
print("响应数据类型为:",type(response))
# 结果为
# 响应数据类型为: <class 'http.client.HTTPResponse'>

在HTTPResponse对象中包含着可以获取响应信息的方法与属性,以向python官网发送网络请求获取响应码,响应头信息、响应头指定信息以及读取HTML代码并进行utf-8编码 ,示例代码如下:

import urllib.request                                   # 导入urllib.request模块
url1 = 'https://www.python.org/'                        # 目标网页的url地址
response = urllib.request.urlopen(url=url1)             # 发送网络请求
print("响应状态码", response.status)
print("响应头所有信息为", response.getheaders())
print("响应头指定信息为", response.getheader('Accept-Ranges'))

print("python官网HTML代码如下:\n",response.read().decode('utf-8'))
#读取HTML代码并进行utf-8解码





运行结果如下:
'''
响应状态码 200
响应头所有信息为 [('Connection', 'close'), ('Content-Length', '50120'), ('Server', 'nginx'), 
('Content-Type', 'text/html; charset=utf-8'), ('X-Frame-Options', 'SAMEORIGIN'), ('Via', '1.1 
vegur, 1.1 varnish, 1.1 varnish'), ('Accept-Ranges', 'bytes'), ('Date', 'Tue, 02 May 2023 09:55:47 
GMT'), ('Age', '884'), ('X-Served-By', 'cache-iad-kiad7000025-IAD, cache-hkg17923-HKG'), ('X-
Cache', 'HIT, HIT'), ('X-Cache-Hits', '21, 15'), ('X-Timer', 'S1683021347.106475,VS0,VE0'), 
('Vary', 'Cookie'), ('Strict-Transport-Security', 'max-age=63072000; includeSubDomains; preload')]
响应头指定信息为 bytes
python官网HTML代码如下:
 <!doctype html>
<!--[if lt IE 7]>   <html class="no-js ie6 lt-ie7 lt-ie8 lt-ie9">   <![endif]-->
<!--[if IE 7]>      <html class="no-js ie7 lt-ie8 lt-ie9">          <![endif]-->
<!--[if IE 8]>      <html class="no-js ie8 lt-ie9">                 <![endif]-->
<!--[if gt IE 8]><!--><html class="no-js" lang="en" dir="ltr">  <!--<![endif]-->

<head>
    <!-- Google tag (gtag.js) -->
    <script async src="https://www.googletagmanager.com/gtag/js?id=G-TF35YF9CVH"></script>
    <script>
    ...(还有很多内容,这里就不全部展出,如果想看就自己运行看一看吧)
'''

发送POST请求

urlopen()方法默认情况下发送的是GET请求,如果需要发送POST请求,可以为其设置data参数,该参数是bytes类型,所以需要用bytes()方法将参数值进行数据类型转化。以向请求测试地址发送POST请求为例,读取响应的HTML代码并进行编码,代码如下:

import urllib.request                      # 导入urllib.request模块
import urllib.parse                        # 导入urllib.requset模块
url1 = 'https://www.httpbin.org/post'      # POST请求测试地址
                                           # 将表单数据转化为bytes类型,并设置编码方式为utf-8
data1 = bytes(urllib.parse.urlencode({'hello': 'python'}), encoding='utf-8')   
response = urllib.request.urlopen(url=url1, data=data1)   # 发送网络请求
print(response.read().decode('utf-8'))      # 读取HTML代码并进行编码

运行结果如下图:
POST请求

请求超时

urlopen()方法中timeout参数,用于设置请求超市,该参数以秒为单位,表示如果在请求时,超出了设置的时间,还没得到响应时就抛出异常。示例代码如下。

import urllib.request       # 导入urllib.request模块
url1 = 'http://python.org/' # 请求地址
# 接下来发送网络请求,设置超时时间为0.1秒
response = urllib.request.urlopen(url=url1, timeout=0.1)
print(response.read().decode('utf-8'))


# 运行结果报错:错误类型TimeoutError: The read operation timed out
由于示例中设置的超时时间为0.1秒,时间较快,所以将会出现超时异常。
将超时时间设置为1秒等合理的时间之后就可以正常获取网页信息

处理网络超时

如果遇到超时异常,爬虫程序将在此处停止。所以在实际开发中开发者可以将超时异常捕获,然后处理下面的爬虫任务,以向python官网发送网络请求为例,将超时参数timeout设置为0.1秒,然后使用try…except捕获异常并判断是超时异常就模拟自动执行下一个任务。示例代码如下:

import urllib.request       # 导入urllib.request模块
import urllib.error         # 导入urllib.error模块
import socket               # 导入socket模块

url1 = 'https://www.python.org/'  # 请求地址
try:
    response = urllib.request.urlopen(url=url1, timeout=0.1)   # 发送网络请求,设置超时时间为0.1秒
    print(response.read().decode('utf-8'))   # 读取HTML代码并进行utf-8编码
except urllib.error.URLError as error:       # 处理异常
    if isinstance(error.reason, socket.timeout):      # 判断异常是否为超时异常
        print("当前任务超时,即将执行下一个任务!")



#运行结果
当前任务超时,即将执行下一个任务!

设置请求头

urlopen()方法能够发送一个最基本的网络请求,但这并不是一个完整的网络请求。如果要构建一个完整的网络请求,还需要添加Headers、Cookies以及代理IP等内容,这样才能更好的模拟一个浏览器所发送的内容。Request类则可以构建一个多种功能的请求对象,其语法格式如下:

urllib.request.Request(url,data=None,headers={},origin_req_host=None,unverifiable=False,method=Nonee)

#参数说明
url : 需要访问的URL完整地址
data : 该参数默认为None,通过该参数确认请求的方式,如果是None,表示请求方式为GET,否则就为POST
headers : 设置请求头部信息,该参数为字典类型。添加请求头信息最常见的用法就是修改User-Agent来伪装成浏览
器。例如,headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0'},表示伪装成火狐浏览器进行网络请求。
origiin_req_host : 用于设置请求方的host名称或者IP。
unverifiable : 用于设置网页是否需要验证,默认为False。
method : 用于设置请求方式,如GET,POST等,默认为GET请求。

注:设置请求头参数是为了模拟浏览器向网页后台发送网络请求,这样可以避免服务器的反爬措施(UA反爬虫:是一种黑名单策略,只要出现在黑名单中的请求,都视为爬虫,对于此类请求将不予处理或返回错误提示。)
使用urlopen()方法发送网络请求时,其本身并没有设置请求头参数,所以向https://www.httpbin.org/post请求测
试地址发送网络请求时,返回的信息中headers将显示如下所示的默认值 :

"headers": {
	"Accept-Encoding": "identity", 
    "Content-Length": "12", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "www.httpbin.org", 
    "User-Agent": "Python-urllib/3.11", 
    "X-Amzn-Trace-Id": "Root=1-6450efd2-0a1e3adb31985e2f73fe7b62"
  },

查看请求头信息:
在这里插入图片描述
如果需要设置请求头信息,首先通过Request类构造一个带有headers请求信息的Request对象,然后为urlopen()方法传入Request对象,再进行网络请求的发送。以向请求测试地址发送POST请求为例:

import urllib.request                      # 导入urllib.request模块
import urllib.parse                        # 导入urllib.parse模块
url1 = 'https://www.httpbin.org/post'      # 请求测试地址
headers1 = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0'}
                                           # 将表单数据转化为bytes类型,并设置编码方式为utf-8
data1 = bytes(urllib.parse.urlencode({'hello': 'python'}), encoding='utf-8')
r = urllib.request.Request(url=url1, data=data1, headers=headers1, method='POST') # 创建Request对象
response = urllib.request.urlopen(r)   # 发送网络请求
print(response.read().decode('utf-8'))      # 读取HTML代码并进行编码


运行结果
{
  "args": {}, 
  "data": "", 
  "files": {}, 
  "form": {
    "hello": "python"
  }, 
  "headers": {
    "Accept-Encoding": "identity", 
    "Content-Length": "12", 
    "Content-Type": "application/x-www-form-urlencoded", 
    "Host": "www.httpbin.org", 
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0", 
    "X-Amzn-Trace-Id": "Root=1-6452604f-332f17b22e19240e74db4fc9"
  }, 
  "json": null, 
  "origin": "120.204.133.134", 
  "url": "https://www.httpbin.org/post"
}

接下来介绍没有设置请求头的情况下直接使用urlopen()方法的优势,以向www.baidu.com发送GET请求为例:

未设置请求头
import urllib.request
url1 = 'https://www.baidu.com'      # 请求测试地址
r = urllib.request.Request(url=url1)   # 创建Request对象
response = urllib.request.urlopen(r)   # 发送网络请求
print(response.read().decode('utf-8'))      # 读取HTML代码并进行编码




运行结果       没有返回百度正常HTML代码
<html>
<head>
	<script>
		location.replace(location.href.replace("https://","http://"));
	</script>
</head>
<body>
	<noscript><meta http-equiv="refresh" content="0;url=http://www.baidu.com/"></noscript>
</body>
</html>

进程已结束,退出代码0









设置了请求头     将返回“百度”正常的HTML代码
import urllib.request
url1 = 'https://www.baidu.com'      # 请求测试地址
headers1 = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0'}                               # 设置请求头      
r = urllib.request.Request(url=url1, headers=headers1)  # 创建Request对象
response = urllib.request.urlopen(r)   # 发送网络请求
print(response.read().decode('utf-8'))      # 读取HTML代码并进行编码



运行结果
<!DOCTYPE html><!--STATUS OK--><html><head><meta http-equiv="Content-Type" content="text/html;
charset=utf-8"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta 
content="always" name="referrer"><meta name="theme-color" content="#ffffff"><meta 
name="description" content="全球领先的中文搜索引擎、致力于让网民更便捷地获取信息,找到所求。百度超过千
亿的中文网页数据库,可以瞬间找到相关的搜索结果。"><link rel="shortcut icon" href="/favicon.ico" 
type="image/x-icon" />
                                (还有很多内容没有展示这里就不再展示)

获取与设置Cookie

Cookie是服务器向客户端返回响应数据时所留下的标记,当客户端再次访问服务器的时候将携带这个标记。一般在实现登陆一个页面时,登陆成功,会在浏览器的Cookie中保留一些信息,当浏览器再次访问时会携带Cookie中的信息,经过服务器核对后便可以确认用户已经登陆过,此时可以直接将登录后的数据直接返回。

模拟登陆

首先要勾选选项 ‘持续记录’

在这里插入图片描述
接下来我们用以登录编程e学网为例:
请添加图片描述

请添加图片描述

在这里我随便输入了用户名和密码进行登录,在此处可以看出登录验证是用POST请求方式以及我们可以点击请求查看表单数据。

接下来我们用pycharm模拟POST请求,实现网页的模拟登陆。

import urllib.request
import urllib.parse
url1 = 'http://sck.mingribook.com:666/index/index/chklogin.html'      # 请求测试地址
data1 = bytes(urllib.parse.urlencode({'username': 'cxk', 'password': 'woshizhenaifen'}), encoding='utf-8')    # 设置表单数据转化为bytes类型,并设置编码方式
headers1 = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/112.0'}      # 设置请求头当然也可以不设置但是在本次示例中结果一样
r = urllib.request.Request(url=url1, data=data1, headers=headers1, method='POST')     # 创建Request对象
response = urllib.request.urlopen(r)         # 发送网络请求
print(response.read().decode('utf-8'))          # 读取HTML代码并进行解码


运行结果
由于作者没有创建相关账户所以返回错误
{"status":false,"msg":"请求错误~"}

获取Cookie

import urllib.request
import urllib.parse
import http.cookiejar
import json
url1 = 'http://sck.mingribook.com:666/index/index/chklogin.html'      # 请求测试地址
data1 = bytes(urllib.parse.urlencode({'username': 'cxk', 'password': 'woshizhenaifen'}), encoding='utf-8')    # 设置表单数据转化为bytes类型,并设置编码方式
cookie = http.cookiejar.CookieJar()  # 创建CookieJar对象
cookie_procerssor = urllib.request.HTTPCookieProcessor(cookie)   #生成Cookie处理器
opener = urllib.request.build_opener(cookie_procerssor)    # 创建opener对象
response = opener.open(url1, data=data1)        # 发送请求
response = json.loads(response.read().decode('utf-8'))['msg']
if response == '登路成功!':     
    for i in cookie:
        print(i.name+'='+i.value)



最后返回的结果类似
PHPSESSID=neldtqstqag1gqgo4jmbnq9fq1

保存Cookie文件

import urllib.request
import urllib.parse
import http.cookiejar
import json
url1 = 'http://sck.mingribook.com:666/index/index/chklogin.html'      # 请求测试地址
data1 = bytes(urllib.parse.urlencode({'username': 'cxk', 'password': 'woshizhenaifen'}), encoding='utf-8')    # 设置表单数据转化为bytes类型,并设置编码方式
cookie_file = 'cookie.txt'                                  #保存Cookie文件
cookie = http.cookiejar.LWPCookieJar(cookie_file)    #创建LWPCookieJar对象

cookie_procerssor = urllib.request.HTTPCookieProcessor(cookie)   #生成Cookie处理器
opener = urllib.request.build_opener(cookie_procerssor)    # 创建opener对象
response = opener.open(url1, data=data1)        # 发送网络请求
response = json.loads(response.read().decode('utf-8'))['msg']
if response == '登路成功!':     
    cookie.save(ignore_discard=True, ignore_expires=True)  # 保存Cookie


由于作者没有相关账号所以就不展示结果了

有了cookie文件就可以调用cookie.load()方法来读取本地的Cookie文件,然后再次向登录的页面发送请求,在‘模拟登陆’部分中的网络请求列表内可以看出,登录验证的请求通过后将自动向登录后的页面地址再次发送请求。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值