版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
第3章抓取静态网页数据《Python网络爬虫基础教程》学习目标/Target了解抓取静态网页的实现技术,能够说出每种实现技术的特点掌握基本请求的发送方式,能够向服务器发送GET请求和POST请求掌握响应内容的处理方式,能够根据需要获取响应内容掌握请求头的定制方式,能够为GET请求和POST请求定制请求头掌握验证Cookie的方式,能够为GET请求和POST请求携带Cookie学习目标/Target掌握保持会话的方式,能够使用Session类的方法实现保持会话掌握SSL证书验证的方式,能够在请求SSL证书失效网站时关闭验证掌握代理服务器的设置方式,能够为请求设置代理服务器掌握异常的处理方式,能够在程序中处理请求超时异常章节概述/Summary静态网页作为早期互联网的主要形式,它的数据直接内嵌于HTML源代码中,是网络爬虫最基础且最易处理的抓取对象。尽管静态网页的结构相对简单,但在实际抓取过程中仍会面临诸多挑战,包括但不限于网站防爬虫、网络请求异常以及数据解析困难等问题。针对这些常见问题,需要采取系统化的解决方案来确保爬虫程序的稳定性。本章将系统性地介绍静态网页数据抓取的完整流程,从基础的请求发起,到复杂的请求参数配置,再到各类防爬虫策略的应对措施。目录/Contents3.13.23.3抓取静态网页的技术发送基本请求处理复杂请求目录/Contents3.43.53.6设置代理服务器处理异常实践项目:抓取黑马程序员论坛的数据抓取静态网页的技术3.1了解抓取静态网页的实现技术,能够说出每种实现技术的特点学习目标3.1抓取静态网页的技术静态网页是由服务器预先生成的完整HTML文档,这种网页的内容在服务器端已经完全确定,不会因用户的请求而产生变化。在静态网页中,所有的数据都直接内嵌在HTML源代码中,无需依赖一些前端技术进行渲染即可完整呈现。因此,抓取静态网页的数据本质上就是获取静态网页的源代码的过程。网络爬虫通过模仿浏览器的行为,向Web服务器发送HTTP请求并接收响应,即可完整获取静态网页的全部数据。3.1抓取静态网页的技术为帮助开发者实现静态网页抓取,Python提供了专门用于发送和接收HTTP请求的编程工具库,包括urllib、httpx和Requests。其中,urllib是Python内置库,无须安装便可以直接在程序中使用;其他都是第三方库,需要另行安装后才可以在程序中使用。3.1抓取静态网页的技术3.1抓取静态网页的技术1.urlliburllib是Python标准库提供的原生HTTP客户端库,主要由urllib.request、urllib.error、urllib.parse和urllib.robotparser共4个核心模块组成,实现完整的网络请求解决方案。作为内置库,urllib无需额外安装,特别适合轻量级网络爬虫的需求或运行环境受限的场景。不过其API设计偏向底层,开发者需要手动处理连接管理、编码转换和Cookies维护等细节,这使得它在实际项目中通常作为备选方案。3.1抓取静态网页的技术2.RequestsRequests是Python生态中非常流行的HTTP客户端库,以简洁优雅的API设计著称。它基于urllib3库实现,提供了高度封装的GET或POST请求方法,能够自动处理URL编码、会话保持和连接复用等复杂细节,全面支持Cookies管理、代理设置和超时控制等核心功能,极大简化了HTTP交互的复杂度,使其成为静态网页数据抓取场景下的标准解决方案。不过,Requests目前仅支持同步请求模式,这是其在异步编程场景中的主要局限。3.1抓取静态网页的技术3.httpxhttpx是新一代高性能HTTP客户端库,在保留与Requests相似API设计的同时,实现了多项重要突破。作为现代化多协议支持库,它不仅完美兼容HTTP/1.1,还原生支持HTTP/2协议,并提供了同步或异步双模式请求能力。该库通过智能编码处理、强类型提示系统以及优化的连接池管理等特性,显著提升了开发体验和运行效率。其内置的超时控制机制和网络适应性调整功能,使其在复杂网络环境下表现出色,特别适合需要协议升级或追求更高性能的项目场景,堪称Requests库的现代化继任者。3.1抓取静态网页的技术综上所述,Python提供了多个各具特色的HTTP客户端库,其中urllib库偏向底层,新兴的httpx库技术支持更多现代特性,但Requests凭借其广泛的应用基础和成熟的生态,已经成为静态网页数据抓取的标准。基于教学示范的普适性考量,本书后续将选择用Requests库进行开发。值得一提的是,Requests是第三方库,需要通过pip工具进行安装,如此便可以在导入程序后直接使用。例如,在当前的开发环境中安装指定版本的Requests库,具体命令如下。pipinstallrequests==2.32.33.1抓取静态网页的技术发送基本请求3.2掌握基本请求的发送方式,能够向服务器发送GET请求学习目标3.2.1发送GET请求当用户在浏览器的地址栏中输入某个URL地址或者单击网页上的某个超链接时,浏览器默认会使用GET方法向服务器发送请求。例如,在浏览器的地址栏中分别输入/和/s?wd=python,访问百度首页和python关键词的查询结果页面时,浏览器实际上发送了GET请求。GET请求是常用的HTTP请求方法,它主要用于从服务器获取资源,会将请求参数以明文形式附加在URL之后,适合获取不需要敏感信息的公开数据。3.2.1发送GET请求在requests库中,get()函数用于向服务器发送GET请求,并获取服务器返回的响应内容。该函数执行时,首先会根据传入的URL自动构建符合标准的请求(每个请求都是Request对象),然后将该请求发送至目标服务器,最后返回结构完整的响应(每个响应都是Response对象)。3.2.1发送GET请求get(url,params=None,headers=None,cookies=None,verify=True,proxies=None,timeout=None,**kwargs)url:必选参数,表示请求的URL。params:可选参数,用于指定目标URL的查询字符串。该参数有3种类型的取值,分别为字典、元组列表和字节序列。如果取值是一个字典,则字典的键为URL查询参数,字典的值为URL查询参数对应的值,例如{"ie":"utf-8","wd":"python"}会被自动编码为?ie=utf-8&wd=python。headers:可选参数,表示请求的请求头,该参数只支持字典类型的值。cookies:可选参数,表示请求的Cookie信息,该参数支持字典或CookieJar类对象。verify:可选参数,表示是否启用SSL证书,默认值为True。proxies:可选参数,用于设置代理服务器,该参数只支持字典类型的值。timeout:可选参数,表示请求网页时设定的超时时长,以秒为单位。3.2.1发送GET请求get()函数会返回Response对象,该对象封装了服务器返回的所有信息,包括响应状态码、响应内容以及响应头。2.携带URL查询参数的GET请求3.2.1发送GET请求下面分别以访问百度首页和在黑马程序员社区搜索“python”的结果页面为例,演示如何使用get()函数发送不携带URL查询参数和携带URL查询参数的GET请求。2.携带URL查询参数的GET请求3.2.1发送GET请求importrequests#准备URLbase_url='/’#根据目标URL向服务器发送GET请求,接收服务器返回的响应信息response=requests.get(url=base_url)#查看响应码print(response.status_code)若GET请求的URL中不需要携带查询参数,则调用get()函数发送GET请求时只需要给url参数传入目标URL即可。例如,使用get()函数发送GET请求访问百度首页,具体代码如下。1.不携带URL查询参数的GET请求3.2.1发送GET请求如果GET请求的URL中需要携带查询参数,那么调用get()函数时可以采用两种方式发送GET请求。第1种方式是将查询参数以“参数名1=值1&参数名2=值2...”的形式拼接到URL的?后面,进而手动构建完整的URL,例如/search.php?mod=forum&searched=1&orderby=lastpost&ascdesc=desc&searchsubmit=yes&kw=python之后将完整的URL传入url参数;第2种方式是将查询参数转换为字典,之后将该字典传入params参数。2.携带URL查询参数的GET请求3.2.1发送GET请求importrequests#准备基本URLbase_url='/search.php'#定义查询参数params='mod=forum&searchid=1&orderby=lastpost&'\'ascdesc=desc&searchsubmit=yes&kw=python'#根据基本URL和查询参数构建完整URLfull_url=base_url+'?'+params#根据完整URL发送GET请求,接收服务器返回的响应信息response=requests.get(full_url,params=params)print(response.status_code)方式一2.携带URL查询参数的GET请求3.2.1发送GET请求importrequests#准备基本URLbase_url='/search.php'#定义查询参数params={'mod':'forum','searchid':'1','orderby':'lastpost','ascdesc':'desc','searchsubmit':'yes','kw':'python'}#根据URL和查询参数发送GET请求,接收服务器返回的响应信息response=requests.get(base_url,params=params)print(response.status_code)方式二2.携带URL查询参数的GET请求掌握基本请求的发送方式,能够向服务器发送POST请求学习目标3.2.2发送POST请求3.2.2发送POST请求如果网页中form表单的method属性设置为POST,用户提交表单时,浏览器会通过POST请求将表单内的所有元素及其对应的数据,作为HTTP请求信息中的请求数据发送至服务器,实现提交数据的功能。例如,登录黑马头条网站时发送的请求是POST请求,使用开发者工具捕获该请求,在标头面板和载荷面板中可以看到该请求相关的内容,具体如图所示。在requests中,post()函数用于向服务器发送POST请求,主要用于向服务器提交数据,比如表单、JSON等。该函数执行时,首先根据目标URL构建请求对象,然后自动处理数据,最后将该请求与数据一并发送给服务器,并返回封装了响应细信息的响应对象。post()函数的声明如下。post(url,data=None,headers=None,cookies=None,verify=True,proxies=None,timeout=None,json=None,**kwargs)3.2.2发送POST请求data:可选参数,用于指定请求发送的表单数据或原始数据。该参数可以接收3种类型的值,分别为字典、字节序列和文件对象。当参数值是一个字典时,字典的键为请求数据的字段,字典的值为请求数据中该字段对应的值,例如{"code":"246810","mobile":"12011111111"}。json:可选参数,用于指定JSON格式的数据,该参数接收字典或列表,并能自动将它们转换成JSON数据,而不需要再手动调用json.dumps()来转换。下面以登录黑马头条网站为例,为大家演示如何使用post()函数提交账号信息,实现用户登录的功能,具体代码如下。importrequests#准备目标URLbase_url='/mp/v1_0/authorizations'#准备请求数据form_data={'mobile':'12011111111','code':'246810'}#向目标URL发送POST请求,自动将请求数据转换为JSON数据,并接收服务器返回的响应信息response=requests.post(base_url,json=form_data)#查看响应信息的状态码print(response.status_code)3.2.2发送POST请求掌握响应内容的处理方式,能够根据需要获取响应内容学习目标3.2.3处理响应当服务器返回的响应状态码为200或201时,说明本次HTTP请求成功,此时可以接收到由服务器返回的响应信息。在Requests库中,Response类的对象中封装了服务器返回的响应信息,这些响应信息包括响应头和响应内容等。除了前面介绍的status_code属性之外,Response类还提供了一些其他属性。3.2.3处理响应属性说明status_code获取服务器返回的状态码text获取字符串形式的响应内容content获取二进制形式的响应内容url获取最终请求的实际URLrequest获取对应的请求对象headers获取响应头encoding设置或获取响应内容的编码格式,与text属性搭配使用cookies获取服务器返回的Cookie虽然text和content属性都能用于获取响应内容,但两者在数据类型和处理方式上存在本质区别。text属性会根据Requests响应头中的Content-Type字段自动进行字符解码,返回处理后的字符串内容,如果未声明编码格式,则会尝试推测,但可能不准确;content属性始终返回原始的二进制字节数据,保留最完整的响应信息,不做任何转换。在实际应用中,text属性适用于处理HTML、JSON等文本数据,而content属性则适用于下载图片、PDF文档等二进制资源。开发者应根据响应内容的类型选择合适的属性,必要时可通过encoding属性手动指定编码格式。3.2.3处理响应通过访问Response类的对象的text属性可以获取字符串形式的响应内容,比如网页源代码。例如,在3.2.1节请求百度首页的示例中,通过text属性获取百度首页的源代码,具体代码如加粗部分所示。3.2.3处理响应importrequests#准备目标URLbase_url='/'#根据目标URL向服务器发送GET请求,接收服务器返回的响应信息response=requests.get(url=base_url)#获取响应内容print(response.text)1.获取网页源代码运行代码,控制台输出了一段HTML代码,按照HTML标准格式调整后的结果如下。3.2.3处理响应1.获取网页源代码运对照浏览器中查看的百度首页源代码可知,标签<title>中的中文文本没有正常显示,而是出现了乱码。这是因为Requests程序推测的编码格式ISO-8859-1与百度首页实际使用的编码格式UTF-8不一致。为了解决这个问题,需要通过Response对象的encoding属性将编码格式设置为UTF-8。在上述示例中获取响应内容之前,增加设置Response对象编码格式的代码,具体代码如加粗部分所示。3.2.3处理响应importrequests#准备目标URLbase_url='/'#根据目标URL向服务器发送GET请求,接收服务器返回的响应信息response=requests.get(url=base_url)#设置响应内容的编码格式response.encoding='utf-8'#获取响应内容print(response.text)1.获取网页源代码再次运行代码,按照HTML标准格式调整后的结果如下。3.2.3处理响应1.获取网页源代码百度首页上除了文字信息之外,还包含一个百度标志(Logo)图片。若希望获取百度Logo的图片,则需要先根据该图片对应的请求URL发送请求,再使用content属性获取该图片对应的二进制数据,并将数据写入本地文件中,具体代码如下。3.2.3处理响应2.获取图片importrequestsbase_url='/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png'response=requests.get(base_url)#获取百度Logo图片对应的二进制数据print(response.content)#将二进制数据写入程序所在目录下的baidu_logo.png文件中withopen('baidu_logo.png','wb')asfile:file.write(response.content)处理复杂请求3.3掌握请求头的定制方式,能够为GET请求和POST请求定制请求头学习目标3.3.1定制请求头在抓取网页数据的过程中,开发者常常要面临网站防爬虫和各类业务需求的双重挑战,这时仅仅发送基本请求往往难以获取目标数据,很有可能出现禁止访问、数据获取失败等问题。为有效解决这些问题,我们必须根据目标网站的具体要求来完善请求配置,例如,通过登录后的Cookies管理会话状态,以访问登录后才能打开的页面内容,定制请求头信息模拟真实浏览器行为等,从而构建普适性强的请求方案,确保在不同场景下都能稳定获取目标数据。3.3.1定制请求头当网络爬虫发送请求抓取网页数据(如豆瓣读书网站标签分类是历史的页面)时,可能会遇到请求被重定向至验证页面、返回虚假数据或完全无响应等情况。之所以遇到这种情况,其实是因为这些网站为防止网络爬虫恶意抓取网页数据加入了防爬虫措施。它们会检查本次请求中请求头包含哪些关键字段,如果发现缺失关键字段,就会判定发送本次请求的客户端不是浏览器,而可能是一个网络爬虫。3.3.1定制请求头3.3.1定制请求头为了解决这个问题,需要为网络爬虫发送的请求定制完整的请求头,使该请求伪装成一个由浏览器发起的请求。请求头主要包括以下几个关键字段。Referer:用于标识当前请求的来源页面URL,是网站实现防盗链机制的重要手段。许多网站会严格校验这个字段,要求访问必须遵循站内正常的页面跳转逻辑,以确保访问逻辑链的完整性。以豆瓣读书为例,要访问历史标签页,合理的访问流程可以是"豆瓣读书首页→历史标签页",而不能是直接访问历史标签页。User-Agent:用于标识客户端的身份,包括类型、操作系统、浏览器版本等信息。3.3.1定制请求头定制请求头分为两步,即查看请求头和设置请求头。下面以豆瓣读书的历史标签页面为例,为大家演示如何查看由浏览器发送请求的请求头信息,并根据该请求头信息设置网络爬虫的请求头。打开Chrome浏览器加载豆瓣读书首页,在首页右侧热门标签中选择“历史”跳转到历史标签页面,打开开发者工具后重新加载该页面。从开发者工具的请求列表中选中刚刚发送的请求,并且在右侧即可以查看该请求对应的请求头信息,具体如图所示。1.查看请求头3.3.1定制请求头字段Referer的值为/,说明当前请求的来源页面是豆瓣读书首页;字段User-Agent的值是一长串内容,包含浏览器类型、版本等一些信息。在Requests中,设置请求头的方式非常简单,只需要在调用请求函数时将定制好的请求头传入headers参数即可。headers参数只能接收字典类型的数据,其中字典的键为请求头中的使用的字段,字典的值为请求头中字段对应的值。例如,使用Requests请求豆瓣读书的历史标签页面,并按照要求设置请求头,具体代码如下。2.设置请求头3.3.1定制请求头importrequestsbase_url='/tag/历史'#定义请求头,用于标识客户端身份和来源页面URLheader={'User-Agent':'Mozilla/5.0(X11;Linuxaarch64)AppleWebKit/537.36(KHTML,likeGecko)Chrome/Safari/537.36CrKey/1.54.250320',Referer':'/'}#根据URL向服务器发送GET请求,设置请求头,接收服务器返回的响应response=requests.get(base_url,headers=header)response.encoding='utf-8'print(response.text)运行代码,控制台输出了一段HTML代码,按照HTML标准格式调整后的结果如下。2.设置请求头3.3.1定制请求头对比从浏览器中查看的源代码可知,程序成功抓取了豆瓣读书历史标签页的源代码。3.3.1定制请求头需要注意的是,如果程序使用同一个User-Agent字段访问网站的频率过高,那么程序也有可能会被网站识别成网络爬虫,并被查封。为解决这个问题,可以收集所有可用的User-Agent,在向服务器发送请求时每隔一段时间便随机选择一个User-Agent,设置动态的请求头。除此之外,还可以使用能够自动生成User-Agent的第三方模块fake-useragent。例如,使用fake-useragent模块随机生成User-Agent,具体代码如下。3.3.1定制请求头fromfake_useragentimportUserAgent#创建UserAgent对象ua=UserAgent()#随机生成任意浏览器的User-Agentprint(ua.random)#随机生成指定浏览器的User-Agentprint(ua.chrome)#Chrome浏览器的User-Agentprint(ua.edge)#Edge浏览器的User-Agentprint(ua.safari)#Safari浏览器的User-Agentprint(ua.firefox)#火狐浏览器的User-Agent掌握请求头的定制方式,能够为GET请求和POST请求携带Cookie学习目标3.3.2验证Cookie当用户首次登录一个网站时,网站往往会要求用户输入用户名和密码,还会提供自动登录选项供用户勾选。如果用户勾选了自动登录选项并成功登录,那么在下一次访问该网站时,不用重复输入用户名和密码便可以进入用户个人主页,这是因为第一次登录时服务器会生成包含加密登录凭证的Cookie,通过响应头发送至浏览器,浏览器会将该Cookie存储到本地硬盘,第二次登录时浏览器会自动在请求头中携带该Cookie,服务器只需要验证Cookie中的加密凭证信息就能确认用户的身份,从而实现免密登录。3.3.2验证CookieCookie是指网站服务器为了辨别用户身份和维持会话状态而存储在浏览器中的小型文本数据,通常不超过4kB。通俗来讲,Cookie是网站用于维持会话状态的小型数据包,由服务器生成并存储在浏览器或用户硬盘中,与普通缓存不同,Cookie专门用于记录用户身份、偏好等状态信息。一个完整的Cookie由一个名称(Name)、一个值(Value)和多个用于控制Cookie有效期、安全性、使用范围的可选属性组成。3.3.2验证Cookie一个完整的Cookie由一个名称(Name)、一个值(Value)和其它多个用于控制Cookie有效期、安全性、使用范围的可选属性组成,这些属性具体如下。Name和Value属性:Cookie的名称及对应的值,其中名称用于标识Cookie的用途,值通常是加密的会话标识或用户凭证。Expires属性:用于设置Cookie的有效期。Cookie的有效期主要有会话性与持久性共两种类型,未设置该属性时为会话性Cookie,会话性Cookie仅仅保存在用户浏览器中,并在关闭浏览器时失效;持久性Cookie会保存在用户的硬盘中,直至生存期到才会失效。Path属性:用于定义了Web站点可以访问Cookie的目录。Domain属性:用于指定可以访问Cookie的Web站点或域。Secure属性:用于指定是否使用安全协议HTTPS发送Cookie。使用安全协议HTTPS,可以保护Cookie在浏览器和服务器间的传输过程中不被窃取和篡改。3.3.2验证Cookie在Requests库中,发送请求时可以通过两种方式携带Cookie,一种方式是直接将包含Cookie信息的请求头传入请求函数的headers参数;另一种方式是将Cookie信息传入请求函数的cookies参数。不过,cookies参数需要接收一个RequestsCookieJar类的对象,该对象类似于一个字典,会以名称(Name)与值(Value)的形式存储Cookie。3.3.2验证Cookieimportrequestsheaders={'Cookie':'此处填写登录百度网站后查看的Cookie信息',#设置字段Cookie'User-Agent':'Mozilla/5.0(Macintosh;IntelMacOSX10_11_4)''AppleWebKit/537.36(KHTML,likeGecko)''Chrome/53.0.2785.116Safari/537.36',}#设置字段User-Agentresponse=requests.get('/',headers=headers)print(response.text)3.3.2验证Cookie下面以百度首页为例,分别通过上述两种方式演示如何使用Requests实现携带Cookie,模拟用户登录后百度首页的访问效果。方式一importrequestsheader={'User-Agent':'Mozilla/5.0(Macintosh;IntelMacOSX10_11_4)''AppleWebKit/537.36(KHTML,likeGecko)Chrome/53.0.2785.116Safari/537.36'}#准备Cookiecookie='此处填写登录百度网站后查看的Cookie信息'jar_obj=requests.cookies.RequestsCookieJar()#创建RequestsCookieJar类的对象#以逗号为分隔符分隔Cookie,并将获得的键和值保存至jar_obj中fortempincookie.split(';'):key,value=temp.split('=',1)jar_obj.set(key,value)response=requests.get('/',headers=header,cookies=jar_obj)print(response.text)3.3.2验证Cookie方式二"userAttr":Number("")||0,"username":"Itcast_001122","unametype":"2","userIsSkined":"off","userIsNewSkined":"off","userSkinName":"","userSkinOpacity":"70",……3.3.2验证Cookie代码的运行结果如下。由加粗部分的运行结果可以看出,程序输出的网页源代码包含了用户名Itcast_001122,说明成功地访问了登录后的百度首页。掌握保持会话的方式,能够使用Session类的方法实现保持会话的效果学习目标3.3.3保持会话在访问拼多多网站时,用户只要登录成功一次,就能以登录状态在多个标签页自由浏览商品,执行查看个人信息、加入购物车、提交订单等一些操作,甚至中途短暂离开拼多多网站后仍然保持登录状态,这正是保持会话的典型应用。保持会话通过在多个请求间持续维护身份凭证和服务器交互状态,给用户提供了不间断的操作体验。3.3.3保持会话会话是Web开发中用于维持用户状态的技术,指用户从登录到退出期间与服务器的完整交互过程,这个过程可以是连续的,也可以是时断时续的。它的核心原理是,服务器为每个用户创建唯一的会话ID(通常由Cookie存储),后续请求通过该ID将用户的多个操作关联起来,从而维持在多个操作之间能够保持连贯性。3.3.3保持会话传统开发若要通过Cookie保持会话,开发者需要手动管理完整的Cookie生命周期:从登录响应头中解析Set-Cookie字段,本地存储Cookie值,在后续请求中手动携带Cookie。这种方式存在明显的问题:一是手动处理容易导致Cookie遗漏或格式错误;二是无法自动感知和处理服务器的Cookie更新;三是每次请求都需要建立新的TCP连接,造成额外的性能开销。这些问题使得手动Cookie管理方式在复杂的会话保持场景中既低效又不可靠。3.3.3保持会话为了能有效解决这些问题,Request库提供Session类来管理会话,它会自动管理几个关键环节,包括自动保存登录后的Cookie并持久化存储;后续请求中智能附加所需的Cookie;通过连接池复用TCP连接提升性能。这种设计使得会话管理变得简单可靠,开发者只需关注业务逻辑,而无需处理底层细节。3.3.3保持会话使用Session类管理会话时,首先需要使用Session()函数创建会话对象,然后通过该对象调用get()或post()方法来发起请求,这些请求会自动携带会话的配置信息,例如已设置的Cookie、默认请求头等,最后在会话使用完毕后,建议使用close()方法来关闭会话,以释放底层连接池占用的资源,避免资源泄漏。3.3.3保持会话importrequests#创建会话对象sess_obj=requests.Session()#发送GET请求sess_obj.get('/cookies/set/sessioncookie/123456789')response=sess_obj.get("/cookies")print(response.text)通过会话不仅可以实现在同一会话内发送多次请求的功能,还可以在跨请求时保持Cookie信息。例如,使用会话对象请求一个测试网站时设置Cookie信息,然后再次请求另一个测试网站来获取当前会话的Cookie信息,具体代码如下。3.3.3保持会话{"cookies":{"sessioncookie":"123456789"}}在上页代码中,首先创建了一个会话对象sess_obj。然后使用sess_obj对象发送了一个GET请求到测试网站,并且在请求该测试网站时设置了Cookie信息。其中Cookie的名称设置为sessioncookie,内容为123456789。最后使用sess_obj对象请求另一个网站,获取上次请求时设置的Cookie信息。运行代码,输出如下结果。3.3.3保持会话importrequestsrequests.get('/cookies/set/sessioncookie/123456789')response=requests.get("/cookies")print(response.text)如果不使用Session类的对象请求测试网站,而直接使用Requests库请求测试网站时,示例代码如下所示。3.3.3保持会话运行程序,结果如下所示。{"cookies":{}}掌握SSL证书验证的方式,能够在请求SSL证书失效网站时关闭验证学习目标3.3.4SSL证书验证大多数网站中都加入了SSL证书,以实现数据信息在浏览器和服务器之间的加密传输,保证双方传递信息的安全性。SSL证书是一种数字证书,类似于驾驶证、护照和营业执照的电子副本,由受信任的数字证书颁发机构CA在验证服务器身份后颁发,具有服务器身份验证和数据传输加密功能。3.3.4SSL证书验证使用Requests调用请求函数发送请求时,由于请求函数的verify参数的默认值为True,所以每次请求网站默认都会进行SSL证书的验证。不过,有些网站可能没有购买SSL证书,或者SSL证书失效。程序访问这类网站时会因为找不到SSL证书而抛出SSLError异常。例如,使用Requests请求测试SSL证书过期的网站,具体代码如下。3.3.4SSL证书验证importrequests#准备目标URL,专门用于测试SSL证书过期的网站base_url='/'header={'User-Agent':'Mozilla/5.0(WindowsNT6.1;Win64;x64AppleWebKit/537.36(KHTML,likeGecko)Chrome/90.0.4430.212Safari/537.36’}#根据目标URL向服务器发送GET请求,默认会进行SSL证书的验证response=requests.get(base_url,headers=header)print(response.status_code)运行上页代码,程序抛出SSLError异常,具体如下所示。3.3.4SSL证书验证(部分省略)requests.exceptions.SSLError:HTTPSConnectionPool(host='',port=443):Maxretriesexceededwithurl:/(CausedbySSLError(SSLCertVerificationError(1,'[SSL:CERTIFICATE_VERIFY_FAILED]certificateverifyfailed:certificatehasexpired(_ssl.c:1028)')))这时需要主动关闭SSL验证,即在调用get()函数时将verify参数设置为False,代码如下所示。#关闭SSL证书的验证response=requests.get(base_url,headers=header,verify=False)再次运行代码,控制台没有输出SSLError异常,而是输出了如下警告信息:3.3.4SSL证书验证E:\基础爬虫第2版\配套资源\源代码\venv\Lib\site-packages\urllib3\connectionpool.py:1097:InsecureRequestWarning:UnverifiedHTTPSrequestisbeingmadetohost''.Addingcertificateverificationisstronglyadvised.See:https://urllib3.readthedocs.io/en/latest/advanced-usage.html#tls-warningswarnings.warn(200这时,如果不希望收到警告信息,可以采用如下方式消除警告信息。importurllib3urllib3.disable_warnings()设置代理服务器3.4掌握代理服务器的设置方式,能够为请求设置代理服务器学习目标3.4.1代理服务器简介设置代理服务器是网络爬虫应对防爬虫的核心策略之一,这种策略会为网络爬虫指定一个代理服务器,将原本由本地主机发起的请求转发至代理服务器,借用其IP地址访问目标网站,从而隐藏网络爬虫所在主机的真实IP地址。3.4.1代理服务器简介网络爬虫在抓取网页的数据时,可能会出现这样的情况:起初可以正常抓取网页的数据,一段时间后便不能继续抓取了,可能会收到403错误及提示信息“您的IP访问频率过高”。之所以出现这种现象是因为网站采取了防爬虫措施,该网站会检测某个IP地址在单位时间内访问的次数,如果超过其设定的阈值,就会直接拒绝为拥有该IP地址的客户端服务,这种情况称为封IP。3.4.1代理服务器简介为避免网络爬虫被封IP,我们可以利用某种技术伪装IP地址,使服务器无法追踪请求的真实设备来源。代理服务器(ProxyServer)是介于客户端与目标服务器之间的中间服务器,其核心功能是代替客户端向目标服务器发起请求,并将获取的响应结果返回给客户端。为帮助大家更好地进行理解。3.4.1代理服务器简介3.4.1代理服务器简介代理服务器如同客户端和Web服务器之间的“中转站”。没有代理服务器之前,客户端会直接将请求发送给Web服务器,Web服务器将响应信息返回给客户端;有了代理服务器之后,客户端先将请求发送到代理服务器,再由代理服务器转发给Web服务器,同时将收到的响应信息返回给客户端。这样一来,网站识别的IP地址是代理服务器的IP地址,而不是客户端的真实IP地址。此外,通过定期更换代理服务器,可进一步降低因单一IP高频访问触发防爬虫的风险。值得一提的是,并非所有的代理服务器都适合网络爬虫。我们在使用代理服务器时,主要考虑代理服务器的匿名程度。根据代理服务器的匿名程度,代理服务器可以分为高度匿名代理服务器、普通匿名代理服务器、透明代理服务器3类。3.4.1代理服务器简介1高度匿名代理服务器会将数据包原封不动地转发给服务器,让服务器认为当前访问的用户只是一个普通客户端,而不是代理服务器,并记录代理服务器的IP地址。2普通匿名代理服务器会对数据包进行一些改动。这时服务器可能会发现当前访问的用户是代理服务器,也可能会追查到客户端的真实IP地址。3透明代理服务器不仅会改动数据包,还会暴露当前访问客户端的真实IP地址。这类代理除了通过缓存提升访问速度、通过内容过滤提高安全性之外,并没有其他显著的作用,常见的场景就是内网中的硬件防火墙。综上所述,免费代理IP是比较容易获取的,不过这类代理IP的质量不高,高度匿名代理IP比较少,有的代理IP很快会失效。如果大家对代理IP的质量要求比较高,或者需要大量稳定的代理IP,那么建议选择一些正规的代理商进行购买。3.4.1代理服务器简介掌握设置代理服务器,能够在requests中设置代理服务器学习目标3.4.2设置代理服务器代理IP主要有3种获取方式,它们分别是获取免费代理IP、获取付费代理IP和ADSL拨号,关于它们的介绍如下。3.4.2设置代理服务器1.获取代理IP1获取免费代理IP免费代理IP通常由公开的代理服务网站提供,无需付费即可获取,适合短期或低频率的爬虫需求。但由于使用人数多,这类IP的稳定性差、速度慢,且可能存在安全风险,需要谨慎筛选和频繁更换。2获取付费代理IP获付费代理IP由专业代理服务商提供,通常具备高匿名性、稳定性和较快的响应速度,适合企业级爬虫或高频访问场景。服务商一般提供API接口或IP池,支持按量或包时计费,并能自动过滤无效IP,可靠性远高于免费代理。3ADSL拨号ADSL拨号代理通过动态拨号更换本地IP(常见于家庭宽带),每次断线重连后获取新IP,能有效绕过IP封禁。这种方式成本低且IP纯净,但切换速度较慢,通常需1~3分钟,适合对时效性要求不高的长期爬虫项目。综上所述,免费代理IP是比较容易获取的,不过这类代理IP的质量不高,高度匿名代理IP比较少,有的代理IP很快会失效。如果大家对代理IP的质量要求比较高,或者需要大量稳定的代理IP,那么建议选择一些正规的代理商进行购买。3.4.2设置代理服务器3.4.2设置代理服务器使用Requests库设置代理IP地址的方式非常简单,只需要在调用请求函数时,通过proxies参数传入一个字典。该字典包含了所需要的代理IP,其中字典的键为协议类型,例如http或https,字典的值为“协议类型://IP地址:端口号”格式的字符串。例如,定义一个包含两个代理IP的字典,代码如下。proxies={'http':'0:3128','https':'0:1080',}2.设置代理IP接下来,通过一个例子演示如何从IP地址列表中随机选择一个IP地址,将该IP地址设置为代理IP,之后基于该代理IP请求小兔鲜儿网首页,具体代码如下。3.4.2设置代理服务器importrequests,random#代理IP地址的列表proxy_list=[{'http':'7:4007'},{'http':':8080'},{'http':'7:80'},{'http':'2:33630'},{'http':'63:3256'}]base_url='/#/'header={'User-Agent':'Mozilla/5.0(WindowsNT6.1;Win64;x64AppleWebKit/537.36(KHTML,likeGecko)''Chrome/90.0.4430.212Safari/537.36'}#发送GET请求,将proxy_list中任意一个IP地址设为代理response=requests.get(base_url,headers=header,proxies=random.choice(proxy_list))print(response.status_code)需要说明的是,上述程序中使用的代理IP是免费的,它们的有效期通常较短且稳定性较差。由于免费代理的可用时间不固定,一旦超过有效时长或被服务商回收,再次运行程序可能会触发ProxyError异常,因此在这里建议大家换用自己查找的代理IP。3.4.2设置代理服务器掌握检测代理IP,能够通过Requests检测代理IP是否有效学习目标3.4.3检测代理IP的有效性互联网上有很多免费的代理IP,但这些IP地址并不都是有效的。因此需要对获取的免费IP地址进行检测,确定IP地址是否有效。检测代理IP有效性的过程比较简单,需要先遍历收集的所有代理IP,将获取的每个代理IP依次设为代理,再通过该IP地址向网站发送请求。如果请求成功,则说明该IP地址是有效的;如果请求失败,则说明该IP地址是无效的,需要被剔除。3.4.3检测代理IP的有效性3.4.3检测代理IP的有效性importrequestsproxy_list=[{'http':'20'},{'http':'50'},{'http':'75'},{'http':'8'},base_url='/#/'header={'User-Agent':'Mozilla/5.0(WindowsNT6.1;Win64;x64AppleWebKit/537.36(KHTML,likeGecko)''Chrome/90.0.4430.212Safari/537.36'}forper_ipinproxy_list.copy():#遍历代理IPtry:response=requests.get(base_url,headers=header,
#发送GET请求,将获取的每个IP地址设置为代理proxies=per_ip,timeout=3)except:
print(f‘IP地址:{per_ip.get(“http”)}无效’)
#发送GET请求,将获取的每个IP地址设置为代理proxy_list.remove(per_ip)else:
print(f'IP地址:{per_ip.get("http")}有效'){'http':'95'}#成功则输出有效IP地址]下面演示如何检测代理IP的有效性,具体代码如下。3.4.3检测代理IP的有效性IP地址:20有效IP地址:50无效IP地址:75无效IP地址:8无效IP地址:95有效运行代码,输出如下结果。处理异常3.5掌握异常的处理方式,能够在程序中处理请求超时异常学习目标3.5处理异常3.5处理异常任何程序在运行过程中都可能会遇到各种各样的问题,网络爬虫自然也不例外。作为依赖网络环境的程序,网络爬虫的抓取操作高度依赖稳定的网络连接,而复杂多变的网络环境(如DNS解析失败、服务器拒绝连接、网络超时等)具有天然的不可控性,这导致网络爬虫每次请求未必能成功获取服务器响应数据。一旦在访问过程中遭遇网络异常,程序往往会触发异常报错并中断运行。3.5处理异常requests.exceptions模块中定义了很多异常类型,常见的异常类型如下表。异常类型说明RequestException异常基类,表示请求过程中的通用异常ConnectionError网络连接失败时抛出HTTPError当HTTP请求返回错误状态码(如4xx、5xx)时抛出URLRequired请求未提供有效的URL地址时抛出TooManyRedirects请求中重定向次数超过最大限制时抛出ConnectTimeout建立网络连接超过指定超时时间时抛出ReadTimeout从服务器读取响应数据超过指定超时时间时抛出Timeout请求整体执行时间超过设置的超时时间时抛出Timeout继承自RequestException,而ConnectTimeout和ReadTimeout又继承自Timeout。3.5处理异常为确保网络爬虫程序能够优雅地处理异常并正常终止,可以通过try-except语句捕获请求过程中可能抛出的异常,并针对不同异常类型执行相应的处理逻辑,比如重试、记录日志或跳过当前请求。这种异常处理机制能有效提升程序的健壮性,避免因未预期的错误导致程序崩溃。3.5处理异常由于网络环境、政策限制等原因,直接请求部分境外网站(如谷歌)可能会因网络连接问题导致网络爬虫程序抛出异常。下面以请求谷歌网站为例,为大家演示如何使用try-except语句捕获RequestException异常,具体代码如下。importtime,requestsprint(time.strftime('开始时间:%Y-%m-%d%H:%
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 上海立信会计金融学院《安全系统工程》2025-2026学年第一学期期末试卷(B卷)
- 上海立信会计金融学院《安全法规》2025-2026学年第一学期期末试卷(B卷)
- 2026年学校实验室耗材管理制度
- 上海立信会计金融学院《Android 系统及开发》2025-2026学年第一学期期末试卷(A卷)
- 上海立信会计金融学院《Android 移动端系统开发》2025-2026学年第一学期期末试卷(A卷)
- 2026年公众演讲台风塑造与紧张克服
- 上海科技大学《安全监察和管理》2025-2026学年第一学期期末试卷(A卷)
- 博野县2025-2026学年三年级数学第一学期期末达标检测试题含解析
- 2026年摩托车发动机发展史与动力演进
- 2026年车辆动态监控平台操作与管理规范
- GB/T 46943-2025临床实验室检测和体外诊断系统病原宏基因组高通量测序性能确认通用要求
- 围产期保健技术培训课件
- 家政公司安全培训课件
- 刑事辩护风险告知书范文模板
- 2025年吉尔吉斯斯坦数字经济发展与跨境电商潜力行业报告
- 高三日语作文评分标准(2026届高三年级11月份联考)
- 烧伤患者镇静与镇痛护理
- 2025年河北省高考历史真题卷(含答案与解析)
- 验收规范考试试题及答案
- 人工智能课件说课稿
- 2025江苏连云港市教育局教研室选调教研员3人(公共基础知识)综合能力测试题附答案解析
评论
0/150
提交评论