数据采集与预处理(微课版) 课件 第2章 数据采集与存储_第1页
数据采集与预处理(微课版) 课件 第2章 数据采集与存储_第2页
数据采集与预处理(微课版) 课件 第2章 数据采集与存储_第3页
数据采集与预处理(微课版) 课件 第2章 数据采集与存储_第4页
数据采集与预处理(微课版) 课件 第2章 数据采集与存储_第5页
已阅读5页,还剩97页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

第二章数据采集与存储“Python数据采集与预处理目录CONTENTS数据类型与操作2.1网页抓取:爬虫基础2.2解析库的使用2.3数据存储2.4学习目标掌握JSON、CSV基础数据的定义格式了解爬虫的基本流程了解什么是HTTP掌握网页的基本元素掌握并熟练使用urllib库掌握并熟练使用requests库掌握并熟练使用正则表达式提取数据了解什么是代理网络掌握并熟练使用解析库BeautifulSoup、XPath解析网页掌握并熟练使用JSON、CSV格式的读取、存储及数据在MySQL数据库的操作数据类型与操作01经常使用AJAX配合JSON来完成任务,比和XML配合容易的多,速度快。如果使用XML,需要读取XML文档,然后用XMLDOM来遍历文档并读取值并存储在变量中。但如果使用JSON,则只需读取JSON字符串。CSV是一种纯文本文件格式,用于存储表格数据(例如电子表格或数据库)。它本质上存储的表格数据包括数字和纯文本。大多数在线服务使用户可以自由地将网站中的数据导出为CSV文件格式。CSV文件通常会在Excel中打开,同时在参加编程马拉松或Kaggle比赛时,通常会提供这种文件格式的语料。从这使用范围方面来看,CSV更加深得程序员的喜爱。2.1数据类型与操作2.1.1数据类型介绍JSON(JavaScriptObjectNotation)是一种轻量级的数据交换格式。它基于JavaScript的一个子集,也就是JavaScript对象标记(1)对象:对象在JavaScript中是使用花括号{}包裹起来的内容,数据结构为{key1:value1,key2:value2,...}的键值对结构。在面向对象的语言中,key为对象属性,value为对应的值。键名可以使用整数和字符串来表示。值的类型可以是任意类型。(2)数组:数组在JavaScript中是方括号[]包裹起来的内容,数据结构为[“java”,“javascript”,“vb”,...]的索引结构。在JavaScript中,数组是一种比较特殊的类型,它也可以像对象那样使用键值对,但还是索引用的多。同样的,值的类型可以是任意类型。2.1数据类型与操作2.1.2JSON格式数据2.1数据类型与操作{"programmers":[{"firstName":"Brett","lastName":"McLaughlin","email":"aaaa"},{"firstName":"Jason","lastName":"Hunter","email":"bbbb"},{"firstName":"Elliotte","lastName":"Harold","email":"cccc"}],"authors":[{"firstName":"Isaac","lastName":"Asimov","genre":"sciencefiction"},{"firstName":"Tad","lastName":"Williams","genre":"fantasy"},{"firstName":"Frank","lastName":"Peretti","genre":"christianfiction"}],"musicians":[{"firstName":"Eric","lastName":"Clapton","instrument":"guitar"},{"firstName":"Sergei","lastName":"Rachmaninoff","instrument":"piano"}]}在不同的主条目(programmers、authors和musicians)之间,记录中实际的名称/值对可以不一样。JSON是完全动态的,允许在JSON结构的中间改变表示数据的方式。逗号分隔值(Comma-SeparatedValues,CSV),有时也称为字符分隔值,因为分隔字符也可以不是逗号,其文件以纯文本形式存储表格数据(数字和文本)。纯文本意味着该文件是一个字符序列,不含必须像二进制数字那样被解读的数据。CSV文件由任意数目的记录组成,记录间以某种换行符分隔。每条记录由字段组成,字段间的分隔符是其它字符或字符串,最常见的是逗号或制表符。通常,所有记录都有完全相同的字段序列。通常都是纯文本文件。CSV的格式规范(格式规范定义来源于RFC4180),一共七点:2.1数据类型与操作2.1.3CSV格式数据(1)每一行记录位于一个单独的行上,用回车换行符CRLF(也就是\r\n)分割。(2)文件中的最后一行记录可以有结尾回车换行符,也可以没有。(3)第一行可以存在一个可选的标题头,格式和普通记录行的格式一样。标题头要包含文件记录字段对应的名称,应该有和记录字段一样的数量。(在MIME类型中,标题头行的存在与否可以通过MIMEtype中的可选“header”参数指明)。(4)在标题头行和普通行每行记录中,会存在一个或多个由半角逗号(,)分隔的字段。整个文件中每行应包含相同数量的字段,空格也是字段的一部分,不应被忽略。每一行记录最后一个字段后不能跟逗号(通常用逗号分隔,也有其他字符分隔的CSV,需事先约定)。(5)每个字段可用也可不用半角双引号(’’)括起来(不过有些程序,如Microsoft的Excel就根本不用双引号)。如果字段没有用引号括起来,那么该字段内部不能出现双引号字符。(6)字段中若包含回车换行符、双引号或者逗号,该字段需要用双引号括起来。(7)如果用双引号括字段,那么出现在字段内的双引号前必须加一个双引号进行转义。2.1数据类型与操作网页抓取:爬虫基础02网络爬虫(又称为网页蜘蛛,网络机器人),是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本。网络爬虫按照系统结构和实现技术,大致可以分为以下几种类型:通用网络爬虫(GeneralPurposeWebCrawler)、聚焦网络爬虫(FocusedWebCrawler)、增量式网络爬虫(IncrementalWebCrawler)、深层网络爬虫(DeepWebCrawler)。

实际的网络爬虫系统通常是几种爬虫技术相结合实现的。2.2网页抓取:爬虫基础2.2.1爬虫基本流程介绍0105040203通用网络爬虫获取初始URL。初始的URL地址可以由人为地指定,也可以由用户指定的某个或几个初始爬虫网页决定。根据初始的URL爬取页面并获得新的URL。获得初始的URL地址之后,首先需要爬取对应URL地址中的网页,爬取了对应的URL地址中的网页后,将网页存储到原始数据库中,并且在爬取网页的同时,发现新的URL地址,同时将已经爬取的URL地址存放到一个URL列表中保存,用于去重以及判断爬取的进程。将新的URL放到URL队列中。在第2步中,获取到了下一个新的需要爬取的URL地址后,会将新的URL地址放到URL队列中。从URL队列中读取新的URL,并依据新的URL爬取网页,同时从新网页中获取URL,并存放上述爬取过程。满足爬虫系统设置的停止条件时,停止爬取。在编写爬虫的时候,一般会设置相应的停止条件。2.2网页抓取:爬虫基础聚焦网络爬虫04030201从新的URL中过滤掉与爬取目标无关的链接。因为聚焦网络爬虫对网页的爬取是有目的性的,所以与目标无关的网页将会被过滤掉。同时,也需要将已爬取的URL地址存放到一个URL列表中,用于去重和判断爬取的进程。根据初始的URL爬取页面,并获取新的URL。获取初始URL。爬取目标的定义和描述。在聚焦网络爬虫中,我们首先要依据爬取需求定义好该聚焦网络爬虫爬取的目标,以及进行相关的描述。2.2网页抓取:爬虫基础聚焦网络爬虫08070605满足系统中设置的停止条件时,或无法获取新的URL地址时,则停止爬虫行为。从下一步要爬取的URL地址中,读取新的URL,然后依据新的URL地址爬取网页,并重复上述爬取过程。从URL队列中,根据搜索算法,确定URL的优先级,并确定下一步要爬取的URL地址。在通用网络爬虫中,下一步爬取哪些URL地址,是不太重要的,但是在聚焦网络爬虫中,不同的爬取顺序,可能导致爬虫的执行效率不同,所以,我们需要依据搜索策略来确定下一步需要爬取哪些URL地址。将过滤后的链接放到URL队列中。2.2网页抓取:爬虫基础

超文本传输协议(HyperTextTransferProtocol,HTTP),

是互联网上应用最为广泛的一种网络协议。所有WWW文件都必须遵守这个标准。它可以使浏览器更加高效,使网络传输减少。它不仅保证计算机正确快速地传输超文本文档,还确定传输文档中的哪一部分,以及哪部分内容首先显示(如文本先于图形)等。2.2网页抓取:爬虫基础2.2.2HTTP基本原理2.2网页抓取:爬虫基础HTTP协议采用URL作为定位网络资源的标识,URL格式如下:http://host[:port][path]host:合法的Internet主机域名或IP地址port:端口号,缺省端口为80path:请求资源的路径HTTPS(HyperTextTransferProtocoloverSecureSocketLayer):超文本传输安全协议。通俗讲HTTPS就是HTTP的安全版,通过它传输的内容都是经过SSL加密的。爬虫抓取的页面通常都是HTTP或HTTPS协议的。当我们打开浏览器,从一个站点点击链接进入下一个站点,就相当于从超文本的一个空间进入另一个空间,浏览器再将其解析出来,就是我们看到的页面了。HTTP是一个应用层协议,是我们想从服务器端获取信息的最直观的请求。比如,在爬虫中使用的<urllib模块>,<requests模块>等都是封装了HTTP协议,作为一个HTTP客户端实现了博文,图片,视频等信息源的下载。但是HTTP也不是直接就可以用的,它的请求是建立在一些底层协议的基础上完成的。如TCP/IP协议栈中,HTTP需要TCP的三次握手连接成功后才能向服务器发起请求。当然,如果是HTTPS的话,还需要TSL和SSL安全层。2.2网页抓取:爬虫基础互联网的关键技术就是TCP/IP协议。两台计算机之间的通信是通过TCP/IP协议在因特网上进行的。实际上这个是两个协议:TCP(TransmissionControlProtocol,传输控制协议)和IP(InternetProtocol,网际协议)。TCP/IP就是TCP和IP两个协议在一起协同工作,有上下层次的关系。TCP负责应用软件(比如你的浏览器)和网络软件之间的通信。IP负责计算机之间的通信。TCP负责将数据分割并装入IP包,IP负责将包发送至接受者,传输过程要经IP路由器负责根据通信量、网络中的错误或者其他参数来进行正确地寻址,然后在它们到达的时候重新组合它们。IP:计算机之间的通信。IP协议是计算机用来相互识别的通信的一种机制,每台计算机都有一个IP。用来在internet上标识这台计算机。IP负责在因特网上发送和接收数据包。通过IP,消息(或者其他数据)被分割为小的独立的包,并通过因特网在计算机之间传送。IP负责将每个包路由至它的目的地。IP协议仅仅是允许计算机相互发消息,但它并不检查消息是否以发送的次序到达而且没有损坏(只检查关键的头数据)。为了提供消息检验功能,直接在IP协议上设计了传输控制协议TCP。2.2网页抓取:爬虫基础HTTP工作过程,一次HTTP操作称为一个事务,其工作整个过程如下:(1)地址解析。如用客户端浏览器请求这个页面::8080/index.html从中分解出协议名、主机名、端口、对象路径等部分,对于我们的这个地址,解析得到的结果如下:①协议名:http②主机名:③端口:8080④对象路径:/index.htm在这一步,需要域名系统DNS解析域名,得主机的IP地址。(2)封装HTTP请求数据包。把以上部分结合本机自己的信息,封装成一个HTTP请求数据包2.2网页抓取:爬虫基础3)封装成TCP包,建立TCP连接(TCP的三次握手)。在HTTP工作开始之前,客户机(Web浏览器)首先要通过网络与服务器建立连接,该连接是通过TCP来完成的,该协议与IP协议共同构建Internet,即著名的TCP/IP协议族,因此Internet又被称作是TCP/IP网络。HTTP是比TCP更高层次的应用层协议,根据规则,只有低层协议建立之后才能,才能进行更层协议的连接,因此,首先要建立TCP连接,一般TCP连接的端口号是80。这里是8080端口。(4)客户机发送请求命令建立连接后,客户机发送一个请求给服务器,请求方式的格式为:统一资源标识符(URL)、协议版本号,后边是MIME信息包括请求修饰符、客户机信息和可内容。(5)服务器响应服务器接到请求后,给予相应的响应信息,其格式为一个状态行,包括信息的协议版本号、一个成功或错误的代码,后边是MIME信息包括服务器信息、实体信息和可能的内容。实体消息是服务器向浏览器发送头信息后,它会发送一个空白行来表示头信息的发送到此为结束。接着,它就以Content-Type应答头信息所描述的格式发送用户所请求的实际数据。2.2网页抓取:爬虫基础(6)服务器关闭TCP连接一般情况下,一旦Web服务器向浏览器发送了请求数据,它就要关闭TCP连接,然后如果浏览器或者服务器在其头信息加入了这行代码(Connection:keep-alive)。TCP连接在发送后将仍然保持打开状态,于是,浏览器可以继续通过相同的连接发送请求。保持连接节省了为每个请求建立新连接所需的时间,还节约了网络带宽。使用HTML来建立自己的WEB站点,HTML运行在浏览器上,由浏览器来解析。2.2网页抓取:爬虫基础1.<!DOCTYPEhtml>声明为HTML5文档2.<html>元素是HTML页面的根元素3.<head>元素包含了文档的元(meta)数据,如<metacharset="utf-8">定义网页编码格式为utf-8。4.<title>元素描述了文档的标题5.<body>元素包含了可见的页面内容6.<h1>元素定义一个大标题7.<p>元素定义一个段落2.2.3网页基础1HTML标题2HTML段落3HTML链接4HTML图像5HTML<head>元素6HTML表格2.2网页抓取:爬虫基础7HTML布局8HTML框架网页基础1.HTML标题HTML标题(Heading)是通过<h1>-<h6>标签来定义的。2.2网页抓取:爬虫基础2.HTML段落HTML段落是通过标签<p>来定义的。<h1>这是一个标题</h1><h2>这是一个标题</h2><h3>这是一个标题</h3><p>这是一个段落。</p><p>这是另外一个段落。</p>3.HTML链接HTML链接是通过标签<a>来定义的。<ahref="">这是一个链接</a>4.HTML图像HTML图像是通过标签<img>来定义的。<imgloading="lazy"src="/images/logo.png"width="258"height="39"/>5.HTML<head>元素<head>元素包含了所有的头部标签元素。在<head>元素中你可以插入脚本(scripts),样式文件(CSS),及各种meta信息。可以添加在头部区域的元素标签为:<title>,<style>,<meta>,<link>,<script>,<noscript>和<base>。2.2网页抓取:爬虫基础6.HTML表格表格由<table>标签来定义。每个表格均有若干行(由<tr>标签定义),每行被分割为若干单元格(由<td>标签定义)。字母td指表格数据(tabledata),即数据单元格的内容。数据单元格可以包含文本、图片、列表、段落、表单、水平线、表格等等。<tableborder="1"> <tr> <td>row1,cell1</td> <td>row1,cell2</td> </tr> <tr> <td>row2,cell1</td> <td>row2,cell2</td> </tr></table>7.HTML布局大多数网站会把内容安排到多个列中(就像杂志或报纸那样)。大多数网站可以使用<div>或者<table>元素来创建多列。CSS用于对元素进行定位,或者为页面创建背景以及色彩丰富的外观。2.2网页抓取:爬虫基础8.HTML框架通过使用框架,你可以在同一个浏览器窗口中显示不止一个页面。<iframesrc="URL"></iframe> #格式#示例<iframesrc="demo_iframe.htm"name="iframe_a"></iframe><p><ahref=""target="iframe_a"rel="noopener">RUNOOB.COM</a></p>以上便是一些常用的HTML基础,了解了一些基础的页面构成,有利于读者在后续爬虫时,定位到需要爬取的位置。HTML标签简写及全称速查网址:/html/html-tag-name.htmlurllib库一般用来实现这些功能:向服务器发送请求,得到服务器响应,获取网页的内容。Python的强大就在于提供了功能齐全的类库,来帮助完成这些请求,通过调用urllib库,我们不需要了解请求的数据结构,HTTP、TCP、IP层的网络传输通信,以及服务器应答原理等等。

此外,urllib库是Python内置的HTTP请求库,也就是说不需要额外安装。requests库的更多信息可以从官网/3/library/urllib.request.html浏览查看。2.2网页抓取:爬虫基础2.2.4使用urllib库requsetHTTP请求模块,可以用来模拟发送请求,只需要传入URL及额外参数,就可以模拟浏览器访问网页的过程。error异常处理模块,检测请求是否报错,捕捉异常错误,进行重试或其他操作,保证程序不会终止。parse工具模块,提供许多URL处理方法,如拆分、解析、合并等。robotparser识别网站的robots.txt文件,判断哪些网站可以爬,哪些网站不可以爬,使用频率较少。网络爬虫排除标准(RobotsExclusionStandard)。网站告知网络爬虫哪些页面可以抓取,哪些不行,在网站的根目录下的robots.txt文件。2.2网页抓取:爬虫基础urllib库包含4个模块:urlopen是request模块中的方法,用于模拟浏览器的一个请求发起过程,便于我们抓取网页信息。2.2网页抓取:爬虫基础1.request模块importurllib.request

respons=urllib.request.urlopen('/')#http请求对象print(type(respons))print(respons.read().decode('utf-8'))#调用http请求对象的read()方法读取对象的内容并以utf-8的格式显示出来respons对象主要包含read()、readinto()、getheader(name)、getheaders()、fileno()等方法,以及msg、version、status、reason、debuglevel、closed等属性。下面看一个例子2.2网页抓取:爬虫基础1.request模块importurllib.requestrespons=urllib.request.urlopen('')print(respons.status)print(respons.getheaders())print(respons.getheader('Server'))可以得到了访问百度时的响应状态码和响应的头信息,响应状态码200表示成功访问,然后响应头中的Server值是BWS/1.1,表明服务器是用此搭建的。在网络不好的情况下程序可能会因报错而终止运行,这时异常处理就很重要了。URLError是error异常模块的基类,由request模块生成的异常都可以通过捕获这个类来处理。HTTPError是URLError的子类,专门用来处理HTTP请求错误,比如认证请求失败等,它有三个属性:code:返回HTTP状态码。reason:返回错误的原因。headers:返回请求头。下面举个例子:2.2网页抓取:爬虫基础2.error模块fromurllibimportrequest,errortry:response=request.urlopen('/index.html')excepterror.HTTPErrorase:print(e.reason,e.code,e.headers,sep='\n')就会返回得到,HTTP状态码、返回错误的原因、请求头。urllib库提供了parse模块用以处理URL的标准接口,例如实现URL各部分的抽取,合并以及连接转换。2.2网页抓取:爬虫基础3.parse模块返回结果是一个ParseResult对象,由scheme、netloc、path、params、query、fragment这六部分组成,分别代表协议、域名、访问路径、参数、查询条件、锚点。fromurllib.parseimporturlparseResult=urlparse('/apps/abs/10/297/x7m9k?spm=a2166.8043889.305590.6.59e87482PoG2FO&wh_weex=true&psId=1650038')print(type(result),'\n',result)2.2网页抓取:爬虫基础4.robotts协议也叫爬虫协议,用来告诉爬虫和搜索引擎哪些页面可以爬取,哪些不能。当搜索爬虫访问一个站点时,它首先会检查这个站点根目录下是否存在robots.txt文件,如果存在则会根据其中的爬取范围来爬取,如果没有这个文件,爬虫就会访问所有可直接访问的页面。robotparser模块可用于解析robotts.txt。这个模块提供了一个RobotFileParser可以根据某网站的robots.txt文件来判断一个爬虫是否有权限来爬取这个页面,它有如下一些方法:①set_url():用来设置robots.txt文件的链接,如果在创建RobotFileParser对象时传入了链接就不需要使用这个方法来设置了。②read():读取robots.txt文件并进行分析,这个方法执行一个读取和分析操作,这个方法必须调用。③parse():用来解析robots.txt文件,传入robots.txt某些行的内容,它会按照robots.txt的语法规则来分析这些内容。④can_fetch():传入User-agent和要抓取的URL,返回是否可以抓取这个URL,只有Ture和False。⑤mtime():返回上次抓取和分析robots.txt的时间。⑥modified():将当前时间设置为上次抓取和分析robots.txt的时间。requests库是目前公认的最简洁、最方便的爬取网页的第三方库,甚至可以用一行代码就可以从网页获取爬取的信息。requests库的更多信息可以从官网浏览查看。2.2网页抓取:爬虫基础1.requests库的安装win+R执行命令cmd,执行下面的命令行。pipinstallrequests2.2.5使用requests库请求网站2.2网页抓取:爬虫基础2.测试requests库是否安装成功在IDEA编译器中,测试requests库是否安装成功importrequestsr=requests.get('/')print(type(r))print(r.status_code)print(r.encoding)print(r.cookies)<class'requests.models.Response'>200ISO-8859-1<RequestsCookieJar[<CookieBDORZ=27315for./>]>可以看到下面的输出,即安装成功2.2网页抓取:爬虫基础3.requests库的主要方法requests库常用的主要方法一共有7个,如下:①requests.request(method,url,**kwargs)构造一个请求,支撑以下各方法的基础方法。②requests.get(url,params=None,**kwargs)get()函数时获取HTML网页的主要方法,对应于HTTP的GET,其参数解释如下:a.url:拟获取页面的url链接。b.params:url中的额外参数,字典或字节流格式,可选。c.**kwargs:12个控制访问的参数。r=requests.get(url)d.r:返回一个包含服务器资源的Response对象,Response对象包含服务器返回的所有信息,也包含请求的Request信息。2.2网页抓取:爬虫基础属性说明r.status_codeHTTP请求的返回状态,200表示连接成功,404表示失败r.textHTTP响应内容的字符串形式,即,url对应的页面内容r.encoding从HTTPheader中猜测的响应内容编码方式r.apparent_encoding从内容中分析出的响应内容编码方式(备选编码方式)r.contentHTTP响应内容的二进制形式Response对象属性2.2网页抓取:爬虫基础③requests.head(url,**kwargs)获取HTML网页的头信息方法,对应于HTTP的HEAD。④requests.post(url,data=None,json=None,**kwargs)向HTML网页提交POST请求的方法,对应于HTTP的POST。⑤requests.put(url,data=None,**kwargs)向HTML网页提交PUT请求的方法,对应于HTTP的PUT。⑥requests.patch(url,data=None,**kwargs)向HTML网页提交局部修改请求,对应于HTTP的PATCH。⑦requests.delete(url,**kwargs)向HTML网页提交删除请求,对应于HTTP的DELETE。

可以看出,HTTP协议和requests库访问网页的方法几乎是一一对应,功能一致的。在使用requests库来获取页面信息时,我们主要使用的是get()函数,通过requests.get(url)获取url的相关内容。

但这样的语句并不是一定成立的,因为网络连接有风险,所以这样的语句异常处理很重要。2.2网页抓取:爬虫基础4.requests库的异常处理requests库常用的异常处理方法一共有6个,如下:异常说明requests.ConnectionError网络连接错误异常,如DNS查询失败、拒接连接等requests.HTTPErrorHTTP错误异常requests.URLRequiredURL错误异常requests.TooManyRedirects超过最大重定向次数,产生重定向异常requests.ConnectTimeout连接远程服务器超时异常(仅仅是连接的时间)requests.Timeout请求URL超时,产生超时异常(整个过程)2.2网页抓取:爬虫基础正则表达式可以从一个基础字符串中根据一定的匹配模式替换文本中的字符串、验证表单、提取字符串等等。在Python中,一般会使用re模块来实现Python正则表达式的功能。(正则表达式在线测试平台:/)2.2.6正则表达式提取数据1.正则表达式的基本使用理论(1)基本匹配正则表达式其实就是在执行搜索时的格式,它由一些字母和数字组合而成。例如:一个正则表达式cat,它表示一个规则:由字母c开始,接着是a,再接着是t。"cat"=>Thefatcatsatonthemat.2.2网页抓取:爬虫基础同时,正则表达式是大小写敏感的,若一个正则表达式The,匹配到的是The,而不会匹配the。"The"=>Thefatcatsatonthemat.(2)元字符正则表达式主要依赖于元字符。元字符不代表他们本身的字面意思,他们都有特殊的含义。一些元字符写在方括号中的时候有一些特殊的意思。以表是一些元字符的介绍:2.2网页抓取:爬虫基础元字符描述.句号匹配任意单个字符除了换行符。[]字符种类。匹配方括号内的任意字符。[^]否定的字符种类。匹配除了方括号里的任意字符*匹配>=0个重复的在*号之前的字符。+匹配>=1个重复的+号前的字符。?标记?之前的字符为可选.{n,m}匹配num个大括号之前的字符或字符集(n<=num<=m).(xyz)字符集,匹配与xyz完全相等的字符串.|或运算符,匹配符号前或后的字符.\转义字符,用于匹配一些保留的字符[](){}.*+?^$\|^从开始行开始匹配.$从末端开始匹配.常用的元字符2.2网页抓取:爬虫基础①点运算符“.”是元字符中最简单的例子。“.”匹配任意单个字符,但不匹配换行符。例如,表达式.ar匹配一个任意字符后面跟着是a和r的字符串。".ar"=>Thecar

parkedinthegarage.②字符集字符集也叫做字符类。方括号用来指定一个字符集。在方括号中使用连字符来指定字符集的范围。在方括号中的字符集不关心顺序。例如,表达式[Tt]he匹配the和The。"[Tt]he"=>Thecarparkedinthegarage.方括号的句号就表示句号。表达式ar[.]匹配ar.字符串。"ar[.]"=>Agarageisagoodplacetoparkacar.2.2网页抓取:爬虫基础③否定字符集一般来说^表示一个字符串的开头,但它用在一个方括号的开头的时候,它表示这个字符集是否定的。例如,表达式[^c]ar匹配一个后面跟着ar的除了c以外的任意字符。④重复次数后面跟着元字符+,*or?的,用来指定匹配子模式的次数。这些元字符在不同的情况下有着不同的意思。*号匹配在*之前的字符出现大于等于0次。例如,表达式a*匹配0或更多个以a开头的字符。表达式[a-z]*匹配一个行中所有以小写字母开头的字符串。"[^c]ar"=>Thecarparkedinthegarage."[a-z]*"=>Thecarparkedinthegarage.*字符和.字符搭配可以匹配所有的字符.*。*和表示匹配空格的符号\s连起来用,如表达式\s*cat\s*匹配0或更多个空格开头和0或更多个空格结尾的cat字符串。"\s*cat\s*"=>Thefatcatsatontheconcatenation.2.2网页抓取:爬虫基础+号匹配+号之前的字符出现>=1次。例如表达式c.+t匹配以首字母c开头以t结尾,中间跟着至少一个字符的字符串。在正则表达式中元字符?标记在符号前面的字符为可选,即出现0或1次。例如,表达式[T]?he匹配字符串he和The。⑤{}号在正则表达式中{}是一个量词,常用来限定一个或一组字符可以重复出现的次数。例如,表达式[0-9]{2,3}匹配最少2位最多3位0~9的数字。"c.+t"=>Thefatcatsatonthemat"[T]?he"=>Thecarisparkedinthegarage."[0-9]{2,3}"=>Thenumberwas9.9997butweroundeditoffto10.0.我们可以省略第二个参数。例如,[0-9]{2,}匹配至少两位0~9的数字。"[0-9]{2,}"=>Thenumberwas9.9997butweroundeditoffto10.0.2.2网页抓取:爬虫基础如果逗号也省略掉则表示重复固定的次数。例如,[0-9]{3}匹配3位数字⑥(...)特征标群特征标群是一组写在(...)中的子模式。(...)中包含的内容将会被看成一个整体,和数学中小括号()的作用相同。例如,表达式(ab)*匹配连续出现0或更多个ab。如果没有使用(...),那么表达式ab*将匹配连续出现0或更多个b。再比如之前说的{}是用来表示前面一个字符出现指定次数。但如果在{}前加上特征标群(...)则表示整个标群内的字符重复N次。我们还可以在()中用或字符|表示或。例如,(c|g|p)ar匹配car或gar或par."[0-9]{3}"=>Thenumberwas9.9997butweroundeditoffto10.0."(c|g|p)ar"=>Thecarisparkedinthegarage.⑦|或运算符或运算符就表示或,用作判断条件。例如(T|t)he|car匹配(T|t)he或car。"(T|t)he|car"=>Thecarisparkedinthegarage.2.2网页抓取:爬虫基础⑧转码特殊字符反斜线\在表达式中用于转码紧跟其后的字符。用于指定{}[]/\+*.$^|?这些特殊字符。如果想要匹配这些特殊字符则要在其前面加上反斜线\。例如.是用来匹配除换行符外的所有字符的。如果想要匹配句子中的.则要写成\.以下这个例子\.?是选择性匹配."(f|c|m)at\.?"=>Thefatcatsatonthemat.⑨锚点在正则表达式中,想要匹配指定开头或结尾的字符串就要使用到锚点。^指定开头,$指定结尾。^用来检查匹配的字符串是否在所匹配字符串的开头。例如,在abc中使用表达式^a会得到结果a。但如果使用^b将匹配不到任何结果。因为在字符串abc中并不是以b开头。例如,^(T|t)he匹配以The或the开头的字符串。"(T|t)he"=>Thecarisparkedinthegarage."^(T|t)he"=>Thecarisparkedinthegarage.2.2网页抓取:爬虫基础同理于^号,$号用来匹配字符是否是最后一个。例如,(at\.)$匹配以at.结尾的字符串。"(at\.)"=>Thefatcat.sat.onthemat."(at\.)$"=>Thefatcat.sat.onthemat.(3)简写字符集常用的字符集简写简写描述.除换行符外的所有字符\w匹配所有字母数字,等同于[a-zA-Z0-9_]\W匹配所有非字母数字,即符号,等同于:[^\w]\d匹配数字:[0-9]\D匹配非数字:[^\d]\s匹配所有空格字符,等同于:[\t\n\f\r\p{Z}]\S匹配所有非空格字符:[^\s]\f匹配一个换页符\n匹配一个换行符\r匹配一个回车符\t匹配一个制表符\v匹配一个垂直制表符\p匹配CR/LF(等同于\r\n),用来匹配DOS行终止符2.2网页抓取:爬虫基础(4)零宽度断言先行断言和后发断言都属于非捕获簇(不捕获文本,也不针对组合计进行计数)。先行断言用于判断所匹配的格式是否在另一个确定的格式之前,匹配结果不包含该确定格式(仅作为约束)。例如,我们想要获得所有跟在$符号后的数字,我们可以使用正后发断言(?<=\$)[0-9\.]*。这个表达式匹配$开头,之后跟着0,1,2,3,4,5,6,7,8,9,.这些字符可以出现大于等于0次。符号描述?=正先行断言-存在?!负先行断言-排除?<=正后发断言-存在?<!负后发断言-排除2.2网页抓取:爬虫基础①?=...正先行断言?=...正先行断言,表示第一部分表达式之后必须跟着?=...定义的表达式。返回结果只包含满足匹配条件的第一部分表达式。定义一个正先行断言要使用()。在括号内部使用一个问号和等号:(?=...)。正先行断言的内容写在括号中的等号后面。例如,表达式(T|t)he(?=\sfat)匹配The和the,在括号中我们又定义了正先行断言(?=\sfat),即The和the后面紧跟着(空格)fat。"(T|t)he(?=\sfat)"=>Thefatcatsatonthemat.②?!...负先行断言负先行断言?!用于筛选所有匹配结果,筛选条件为其后不跟随着断言中定义的格式。正先行断言定义和负先行断言一样,区别就是=替换成!也就是(?!...)。表达式(T|t)he(?!\sfat)匹配The和the,且其后不跟着(空格)fat。"(T|t)he(?!\sfat)"=>Thefatcatsatonthemat.2.2网页抓取:爬虫基础③?<=...正后发断言正后发断言记作(?<=...)用于筛选所有匹配结果,筛选条件为其前跟随着断言中定义的格式。例如,表达式(?<=(T|t)he\s)(fat|mat)匹配fat和mat,且其前跟着The或the。④?<!...负后发断言负后发断言记作(?<!...)用于筛选所有匹配结果,筛选条件为其前不跟随着断言中定义的格式。例如,表达式(?<!(T|t)he\s)(cat)匹配cat,且其前不跟着The或the。"(?<=(T|t)he\s)(fat|mat)"=>Thefatcatsatonthemat."(?<!(T|t)he\s)(cat)"=>Thecatsatoncat.2.2网页抓取:爬虫基础(5)标志标志也叫模式修正符,因为它可以用来修改表达式的搜索结果。这些标志可以任意的组合使用,它也是整个正则表达式的一部分标志描述i忽略大小写。g全局搜索。m多行修饰符:锚点元字符^$工作范围在每行的起始。①忽略大小写(CaseInsensitive)修饰语i用于忽略大小写。例如,表达式/The/gi表示在全局搜索The,在后面的i将其条件修改为忽略大小写,则变成搜索the和The,g表示全局搜索。"The"=>Thefatcatsatonthemat."/The/gi"=>Thefatcatsatonthemat.2.2网页抓取:爬虫基础②全局搜索(Globalsearch)修饰符g常用于执行一个全局搜索匹配,即不仅仅返回第一个匹配的,而是返回全部。例如,表达式/.(at)/g表示搜索任意字符(除了换行)+at,并返回全部结果。③多行修饰符(Multiline)多行修饰符m常用于执行一个多行匹配。像之前介绍的(^,$)用于检查格式是否是在待检测字符串的开头或结尾。但我们如果想要它在每行的开头和结尾生效,我们需要用到多行修饰符m。例如,表达式/at(.)?$/gm表示小写字符a后跟小写字符t,末尾可选除换行符外任意字符。根据m修饰符,现在表达式匹配每行的结尾。"/.(at)/"=>Thefatcatsatonthemat."/.(at)/g"=>Thefat

catsatonthemat."/.at(.)?$/"=>Thefatcatsatonthemat.

"/.at(.)?$/gm"=>Thefatcatsatonthemat.2.2网页抓取:爬虫基础(6)贪婪匹配与惰性匹配(Greedyvslazymatching)正则表达式默认采用贪婪匹配模式,在该模式下意味着会匹配尽可能长的子串。我们可以使用?将贪婪匹配模式转化为惰性匹配模式。"/(.*at)/"=>Thefatcatsatonthemat."/(.*?at)/"=>

Thefatcatsatonthemat.2.re模块来实现Python正则表达式正则表达式要进行相应匹配还需要通过正则表达式函数来完成。常见的正则表达式函数有re.match()函数、re.search()函数、全局匹配函数、re.sub()函数,下面我们讲解这些常用函数的使用。2.2网页抓取:爬虫基础(1)re.match()函数如果想要从源字符串的起始位置匹配一个模式,我们可以使用re.match()函数,re.match()函数的使用格式是: re.match(pattern,string,flag)第一个参数代表对应的正则表达式,第二个参数代表对应的源字符,第三个参数是可选参数,代表对应的标志位,可以放模式修正符等信息。importre

str=''pattern='www'result=re.match(pattern,str)result2=re.match(pattern,str).span()print(result)print(result2)2.2网页抓取:爬虫基础程序中,会从string的起始位置进行匹配,如果不满足模式,则会返回None,如果符合要求,则返回匹配成功的结果。此时,正则表达式刚好可以从string的开头进行匹配并匹配成功,所以,可以看到,result、result2都成功进行了匹配,但是展现形式不一样。通过.span()设置可以过滤掉一些信息,只留下匹配成功的结果在源字符串中的位置。2.2网页抓取:爬虫基础(2)re.search()函数我们还可以使用re.search()函数进行匹配,会扫描整个字符串并进行对应的匹配。该函数与re.match()函数最大的不同是,re.match()函数从源字符串的开头进行匹配,而re.search()函数会在全文中进行检索匹配。示例代码如下:importre

str=''pattern='.noon.'res1=re.match(pattern,str)res2=re.search(pattern,str)print(res1)print(res2)2.2网页抓取:爬虫基础可以看出,字符串str的开始位置不符合正则表达式格式,所以match()方法匹配不到结果。但是字符串str中含有符合正则表达式格式的内容,所以search()方法匹配到了结果'unoona'。2.2网页抓取:爬虫基础(3)全局匹配函数上面的两种匹配函数match()、search()方法只返回一个匹配到的结果。那么当需要返回所有符合条件的匹配结果,可以使用全局匹配函数。示例代码如下:importre

str=''#预编译pattern=pile('.noon.')#全局匹配、找出左右符合条件的匹配res=pattern.findall(str)print(res)得到执行结果:['unoona','anoons']。上面功能的实现重点主要是先预编译,在找出所有符合条件的结果。2.2网页抓取:爬虫基础(4)re.sub()函数上面的3个函数都是找出想要的条件的结果,那么当我们想根据正则表达式来替换符合条件的字符串,可以通过sub()实现。re.sub(pattern,rep,string,max)pattern:正则表达式rep:想要的目标字符串string:源字符串max:最多可替换的次数;若忽略,则符合条件的全部替换2.2网页抓取:爬虫基础importre

str=''pattern='.noon.'#全部替换res1=re.sub(pattern,'|**|',str)#替换两次res2=re.sub(pattern,'|**|',str,2)print(res1)print(res2)2.2网页抓取:爬虫基础最初爬虫正常运行,正常抓取数据,一切看起来都是那么美好,然而一会便可能就会出现错误,比如“403Forbidden”,这时候打开网页一看,可能会看到“您的IP访问频率太高”这样的提示。出现这种现象的原因是网站采取了一些反爬虫措施。既然服务器检测的是某个IP单位时间的请求次数,那么借助某种方式来伪装我们的IP,让服务器识别不出是由我们本机发起的请求,不就可以成功防止封IP了吗?一种有效的方式就是使用代理。2.2.7代理的使用1.基本原理在我们正常请求一个网站时,是发送了请求给Web服务器,Web服务器把响应传回给我们。如果设置了代理服务器,实际上就是在本机和服务器之间搭建了一个桥,此时本机不是直接向Web服务器发起请求,而是向代理服务器发出请求,请求会发送给代理服务器,然后由代理服务器再发送给Web服务器,接着由代理服务器再把Web服务器返回的响应转发给本机。这样同样可以正常访问网页,但这个过程中Web服务器识别出的真实IP就不再是本机的IP了,其成功实现了IP伪装,这就是代理的基本原理。2.2网页抓取:爬虫基础2.代理的作用(1)突破自身IP访问限制,访问一些平时不能访问的站点。(2)访问一些单位或团体内部资源:比如使用教育网内地址段免费代理服务器,就可以用于对教育网开放的各类FTP下载上传,以及各类资料查询共享等服务。(3)提高访问速度:通常代理服务器都设置一个较大的硬盘缓冲区,当有外界的信息通过时,同时也将其保存到缓冲区中,当其他用户再访问相同的信息时,则直接由缓冲区中取出信息,传给用户,以提高访问速度。(4)隐藏真实IP:上网者也可以通过这种方法隐藏自己的IP,免受攻击。对于爬虫来说,我们用代理就是为了隐藏自身IP,防止自身的IP被封锁。2.2网页抓取:爬虫基础3.代理分类根据代理的协议,代理可以分为如下类别:①FTP代理服务器:主要用于访问FTP服务器,一般有上传、下载以及缓存功能,端口一般为21、2121等。②HTTP代理服务器:主要用于访问网页,一般有内容过滤和缓存功能,端口一般为80、8080、3128等。③SSL/TLS代理:主要用于访问加密网站,一般有SSL或TLS加密功能(最高支持128位加密强度),端口一般为443。④RTSP代理:主要用于访问Real流媒体服务器,一般有缓存功能,端口一般为554。⑤Telnet代理:主要用于telnet远程控制(黑客入侵计算机时常用于隐藏身份),端口一般为23。⑥POP3/SMTP代理:主要用于POP3/SMTP方式收发邮件,一般有缓存功能,端口一般为110/25。⑦SOCKS代理:只是单纯传递数据包,不关心具体协议和用法,所以速度快很多,一般有缓存功能,端口一般为1080。SOCKS代理协议又分为SOCKS4和SOCKS5,前者只支持TCP,而后者支持TCP和UDP,还支持各种身份验证机制、服务器端域名解析等。简单来说,SOCK4能做到的SOCKS5都可以做到,但SOCKS5能做到的SOCK4不一定能做到。(1)根据协议区分2.2网页抓取:爬虫基础根据代理的匿名程度,代理可以分为如下类别:①高度匿名代理:会将数据包原封不动地转发,在服务端看来就好像真的是一个普通客户端在访问,而记录的IP是代理服务器的IP。②普通匿名代理:会在数据包上做一些改动,服务端上有可能发现这是个代理服务器,也有一定几率追查到客户端的真实IP。代理服务器通常会加入的HTTP头有HTTP_VIA和HTTP_X_FORWARDED_FOR。③透明代理:不但改动了数据包,还会告诉服务器客户端的真实IP。这种代理除了能用缓存技术提高浏览速度,能用内容过滤提高安全性之外,并无其他显著作用,最常见的例子是内网中的硬件防火墙。④间谍代理:指组织或个人创建的用于记录用户传输的数据,然后进行研究、监控等目的的代理服务器。(2)根据匿名程度区分2.2网页抓取:爬虫基础爬虫关于cookie和session,由于http协议无记忆性,比如说登录淘宝网站的浏览记录,下次打开是不能直接记忆下来的,后来就有了cookie和session机制。第一次登录后,短时间内再次打开此页面时,会发现系统已经保存了cookie,不用再重新登录。时间长了cookie会失效,需重新登录。所以通过网页捕获cookie就可以实现自动登录了。使用cookie登录方式如下:打开浏览器控制台F12,点击网络、headers,可以看见cookie后的信息。2.2.8使用Cookie登录2.2网页抓取:爬虫基础利用从浏览器获取的cookie信息,我们就可以实现自动登录了。尝试以下代码:fromurllibimportrequest

if__name__=='__main__':url="/3247429/profile"headers={#Cookie值从登录后的浏览器,拷贝,见上"Cookie":"cookie值"}req=request.Request(url=url,headers=headers)rsp=request.urlopen(req)html=rsp.read().decode()withopen("rsp.html","w",encoding="utf-8")asf:print(html)f.write(html)解析库的使用032.3解析库的使用BeautifulSoup是一个可以从HTML或XML文件中提取数据的Python库。它能够通过你喜欢的转换器实现惯用的文档导航,查找,修改文档的方式。BeautifulSoup会帮你节省数小时甚至数天的工作时间。2.3.1使用BeautifulSoup解析网页(1)安装BeautifulSoupwin+R执行命令cmd,执行下面的命令行。显示安装成功即可。

pipinstallbeautifulsoup4(2)BeautifulSoup解析器HTML相当于一个标签树,所以BeautifulSoup库相当是一个解析、遍历、维护“标签树”的功能库。BeautifulSoup类的常用解析器2.3解析库的使用解析器使用方法条件bs4的HTML解析器BeautifulSoup(mk,'html.parser')安装bs4库lxml的HTML解析器BeautifulSoup(mk,'lxml')pipinstalllxmllxml的XML解析器BeautifulSoup(mk,'xml')pipinstalllxmlhtml5lib的解析器BeautifulSoup(mk,'hmtl5lib')pipinstallhtml5lib(3)HTML内容的遍历方法①标签树的下行遍历:2.3解析库的使用.contents:子节点的列表,将<tag>所有儿子节点存入列表.children:子节点的迭代类型,与.contents类似,用于循环遍历儿子节点.descendants:子孙节点的迭代类型,包含所有子孙节点,用于循环遍历②标签树的上行遍历:.parents:节点的父亲标签.parents:节点先辈标签的迭代类型,用于循环遍历先辈节点③标签树的平行遍历:.next_sibling:返回按照HTML文本顺序的下一个平行节点标签.previous_sibling:返回按照HTML文本顺序的上一个平行节点标签.nest_siblings:迭代类型,返回按照HTML文本顺序的后续所有平行节点标签.previous_sibling:迭代类型,返回按照HTML文本顺序的前续所有平行节点标签(4)基本元素2.3解析库的使用Tag:标签,最基本的信息组织单元,分别用<></>标明开头和结尾Name:标签的名字,<p>..</p>的名字是‘p’,格式:<tag>.nameAttributes:标签的属性,字典形式组织,格式:<tag>.attrsNavigableString:标签内非属性字符串,<>..</>中字符串,格式:<tag>.stringComment:标签内字符串的注释部分,一种特殊的Comment类型(5)获取标签节点信息的方法2.3解析库的使用获取标签节点信息方法说明<>.find()搜索且只返回一个结果,字符串类型,同.find_all()参数<>.find_parents()在先辈节点中搜索,返回列表类型,同.find_all()参数<>.find_parent()在先辈节点中返回一个结果,字符串类型,同.find_all()参数<>.find_next_siblings()在后续平行节点中搜索,返回列表类型,同.find_all()参数<>.find_next_sibling()在后续平行节点中返回一个结合,字符串类型,同.find_all()参数<>.find_previous_siblings()在前续平行节点中搜索,返回列表类型,同.find_all()参数<>.find_previous_sibling()在前续平行节点中返回一个结合,字符串类型,同.find_all()参数2.3解析库的使用在进行网页抓取的时候,分析定位html节点是获取抓取信息的关键,目前我用的是lxml模块(用来分析XML文档结构的,当然也能分析html结构),利用其lxml.html的xpath对html进行分析,获取抓取信息。2.3.2使用XPath来处理HTML(1)首先,我们需要安装一个支持xpath的Python库。(2)XPATH常用规则基本上是用一种类似目录树的方法来描述在XML文档中的路径。比如用“/”来作为上下层级间的分隔。第一个“/”表示文档的根节点(注意:不是指文档最外层的tag节点,而是指文档本身)。比如对于一个HTML文件来说,最外层的节点应该是“/html”。pipinstalllxml2.3解析库的使用表达式描述nodename选取测节点的所有子节点/从当前节点选取直接子节点//从当前节点选取子孙节点.选取当前节点..选取当前节点的父节点@选取属性XPATH目录树2.3解析库的使用XPATH代码可见书,节选关键代码如下:fromlxmlimportetreeetree_html=etree.HTML(html1)#自动补全网页格式,并解析为xpath能解析的命令result=etree.tostring(etree_html)#查看自动补全后的网页result_0=etree_html.xpath('//ul//a')#查找ul的间接子孙节点aresult_1=etree_html.xpath('//li[@class="first-li"]')#查找class为first_li的节点result_2=etree_html.xpath('//ul/li')#查找ul下的直接子节点liresult_3=etree_html.xpath('//ul/..')#查找ul的父节点divresult_4=etree_html.xpath('//ul//a/text()')#提取文本信息result_5=etree_html.xpath('//ul//a/@href')#提取属性信息2.3解析库的使用另外一点,若是在浏览器中,有直接获取xpath的方法:F12开发者工具,找到对应的元素,在标签上右键,就可以看到一个copyxpath直接复制即可。数据存储042.4数据存储经过解析器解析出数据之后,接下来就是存储数据了。保存的形式可以多种多样,最简单的形式是直接保存为文本文件,如TXT、JSON、CSV等。另外,还可以保存到数据库中,如关系型数据库MySQL、SQLite、Oracle、DB2等,非关系型数据库MongoDB、Redis等。2.4.1存储为JSON格式(1)读取JSONPython中提供了简单易用得JSON库来实现JSON文件的读写操作,我们可以调用JSON库的loads()方法将JSON文本字符串转为JSON对象,可以通过dumps()方法将JSON对象转换为文本字符串。例如,这里有一段JSON形式的字符串,它是str类型,用Python将其转换为可操作的数据结构,如列表或字典:2.4数据存储这里使用loads()方法将字符串转为JSON对象。由于最外层是中括号,所以最终的类型是列表属性。这样一来,我们就可以用索引来获取对应的内容了。例如,如果想取第一个元素里的name属性,就可以使用如下方式:importjson

str='''[{"name":"Bob","gender":"male","birthday":"1992-02-21"},{"name":"Selian","gender":"female","birthday":"1994-04-12"}]'''

print(type(str))data=json.loads(str)print(data)print(type(data))2.4数据存储这里我们尝试获取年龄age,其在原字典中该键名并不存在,此时默认会返回None。如果传入第二个参数(即默认值),那么在不存在的情况下返回该默认值。data[0]['name']data[0].get('name')上面得到的结果都是:Bob。通过中括号加0索引,可以得到第一个字典元素,然后再调用其键名即可得到相应的键值。获取键值时有两种方式,一种是中括号加键名,另一种是通过get()方法传入键名。这里推荐使用get()方法,这样如果键名不存在,会返回None。另外,get()方法还可以传入第二个参数(即默认值),实例如下:data[0]['age']data[0].get('age',25)运行结果如下:None252.4数据存储值得注意的是,JSON的数据格式需要用双引号来包围,不能使用单引号。例如,若使用如下形式表示,则会出现错误importjson

str='''[{‘name’:’Bob’,‘gender’:’male’,‘

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论