当前位置: 首页 > 后端技术 > Python

Python爬虫requests&BeautifulSoup

时间:2023-03-25 19:48:27 Python

requests模块介绍相对于python自带的urllib模块,requests模块提供了一个相对更高级的网页访问API。对于requests模块,使用起来非常简单。一般我们会用到两个函数:requests.get(url,params=None,**kwargs)其中params就是我们要传入的query,它的格式是dict。requests.post(url,data=None,**kwargs)这里的data就是我们要提交的表单数据,直接传给dict就好了。以上两个函数分别对应http协议中的“GET”方法和“POST”方法。除了这两种方法外,还有“PUT”和“DELETE”等方法。requests模块中有一个统一的函数来发起不同的“Method”HTTP请求报文:requests.request(method,url,**kwargs)可以看到这个函数第一个参数method的值为“GET”,“POST”等。该方法的返回值和上面提到的两个方法都是requests.Response对象。稍后我们将介绍对象和requests.Request对象。比较常用的关键字参数:params、data、headers、proxies、streamwait。其实上面介绍的get和post这两个函数,或者其他方法对应的函数,都是使用request.requests函数实现的:defget(url,params=None,**kwargs):kwargs.setdefault('allow_redirects',true)#这里可以看到request.get的本质returnrequest('get',url,params=params,**kwargs)这里详细介绍headers,proxies,stream关键字参数的作用:headers参数是http请求报文的头部,它的格式是dict,最常用的headers元素是User-Agent,它模仿浏览器访问网页。proxies参数是代理,其格式也是一个dict,每个键值对的形式为:"protocol":"ip:port"。stream参数是前两个比较陌生的参数。该参数默认为False,表示我们会一次性下载所有网页内容,但是如果主动设置为True,则不会立即下载网页内容,而是会等到使用requests的iter_content.response来迭代下载并将数据读入内存。requests.Request&requests.Response这两个对象对于详细了解过爬虫的朋友来说并不陌生。它们是爬虫逻辑中的两个关键对象。简单地说:发送请求并返回响应。requests.Request我们在使用requests的时候一般不会直接创建Request对象,所以这里可以大概了解一下:requests.Request(method=None,url=None,headers=None,data=None,params=None)我们列出Request类的构造需要的一些常用参数,而前面我们提到requests.get等函数的本质就是requests.request函数,所以实际研究一下这个函数的源码:defrequest(method,url,**kwargs):withsessions.Session()assession:#可以看到请求函数中调用了session.request方法returnsession.request(method=method,url=url,**kwargs)#这是session.request方法的定义defrequest(self,method,url,params=None,data=None,headers=None,cookies=None,files=None,auth=None,timeout=None,allow_redirects=True,proxies=None,hooks=None,stream=None,verify=None,cert=None,json=None):#可以看到传入的参数其实是用here#创建一个requests.Request实例req=Request(method=method.upper(),url=url,headers=headers,files=files,data=dataor{},json=json,params=paramsor{},auth=auth,cookies=cookies,挂钩s=hooks,)#进一步处理,得到对应的PreparedRequest对象prep=self.prepare_request(req)proxies=proxiesor{}settings=self.merge_environment_settings(prep.url,proxies,stream,verify,cert)#发送请求.send_kwargs={'timeout':timeout,'allow_redirects':allow_redirects,}send_kwargs.update(settings)#这里是真正的发送Request,并返回一个Response对象resp=self.send(prep,**send_kwargs)returnresp从上面的代码可以看出,requests.request方法的本质是创建一个Request实例,经过一些预处理后发送,然后得到Responserequests.Response我们之前的requests.get,requests.post或者requests.request的函数的返回对象是一个requests.Response实例。对于Response类,我们主要介绍几个常用的属性和方法:Response.content以字节的形式获取返回的Response的内容,其实就是未解码的html文件Response.text文本形式的Response的内容,即解码后的html文件,如果Response.encoding属性为None,则使用chardet猜测字节内容的编码方式。当然,我们也可以在access属性前手动指定一种编码方式。Response.encoding指定如何解码。Response内容的编码完全基于HTTP头,遵循RFC2616文档。Response.url是Response的urlResponse.status_code对应的状态码。如果成功则值为200。Response.request获取到这个Response对应的Request对象,其实就是(PreparedRequest)。通过这个请求对象,我们可以得到访问时的url、方法、headers等属性。Response.iter_content(chunk_size=1),这个函数返回一个generator,它的chunk_size决定了我们每次下载多少字节读入内存,一般的使用方法是for循环likeforiteminResponse.iter_content(256)是可以遍历的。BeautifulSoupBeautifulSoup是一个Python库,可以从HTML或XML文件中提取数据。通常我们使用requests获取html文件(Response.text),然后使用BeautifulSoup进行处理。以便提取我们需要的信息。如何使用BeautifulSoupfrombs4importBeautifulSoup#其中html是返回的网页文本,也就是response.text#lxml是BeautifulSoup使用的文档解析器,我们需要提前#havepip安装lxml模块,或者我们也可以#使用python自带的html.parser,但是速度较慢#而soup是一个BeautifulSoup对象,它携带了一个由html文档内部的各种元素组成的#Tree结构。soup=BeautifulSoup(html,"lxml")#下面是一些最简单基础的用法#直接通过属性引用print(soup.a)获取html文档中的第一个a标签#进一步获取html文档中的第一个a标签htmldocumentThestringpartofanatag(ifitexists)print(soup.a.string)#获取html文档中第一个a标签的href属性值print(soup.a["href"])以上大致介绍了BeautifulSoup的简单实用性,接下来我们更详细地分析一下:BeautifulSoup将HTML文档转换成一个复杂的树结构,树结构中的每个节点都是一个Python对象,所有对象可以分为4种类型:标签,NavigableString,BeautifulSoup,评论。Tag对象对应于html文档中的标签。它有很多属性和方法。这里有两个最重要的属性:1.tag.name返回tag标签的名字(比如tag对应一个标签,那么tag.name返回“a”)。2.tag.attrs以字典的形式返回tag的所有属性,如{"herf":"www.baidu.com"}。而如果我们要获取属性值,我们可以使用tag.attrs["href"],但是我们上面已经看到了,可以直接简写为tag["href"]。NavigableString对象其实就是我们在使用soup.a.string时实际返回的对象。它是python自带的字符串对象的包装器。我们可以把它当作一个字符串来使用,而不用担心其他事情。BeautifulSoup对象对应的就是我们文档的全部内容,也就是上面的soup对象。大多数时候我们可以把它当作一个标签对象来使用,但是它没有attrs属性,它的name属性的值只有:["document"]。Comment对象对应html文档中的comment标签:,这个标签很特殊,不会被浏览器显示,它只是给程序员的一个注释。该对象在实际应用中很少用到,这里不再做介绍。接下来,我们将进一步介绍标签对象和BeautifulSoup对象使用方法:所谓方法使用,我们着重在获得的BeautifulSoup对象的树结构中搜索需要的信息。这种搜索工作根据节点本身信息的应用和树结构中节点之间的关系分为两种类型。第一种是根据自身信息搜索节点:所谓的tag.a其实就是tag.find("a"),该方法具体函数头如下find(name,attrs,recursive,string,**kwargs)name是标签名,它的值是一个“过滤器”。attrs是name对应的label的属性,同值也是一个“filter”。recursive是一个bool值,默认为True。意思是搜索当前标签的所有后代节点。如果为False,则只搜索当前标签的直接子节点。string是name对应的字符串值,也是一个“过滤器”。**kwargs通常被忽略。当然上面的tag.a或者tag.find("a")只能得到tag下的第一个a标签,局限性太大。如果我们想要第三个标签落后怎么办?于是就有了tag.find_all("a")方法,返回一个列表得到所有的a标签,简称tag("a")。find_all(name,attrs,recursive,string,**kwargs)参数的含义与find函数相同。让我们解释一下这个所谓的“过滤器”是什么。具体的代码实现有点繁琐,但是我们可以理解为一个对象,我们允许这个对象有多个值。(1)最简单的字符串值就是传入一个字符串值,比如前面的tag.a(2)正则表达式值,形式为re.compile(r"\d+")(3)列表值就像name=["a","div"],那么find只会返回后者,而find_all会返回一个包含该标签下所有a和div标签的列表。(4)True表示不过滤。对于find,返回tag下第一个符合要求的tag,对于find_all,返回all。比如name=True,那么name就不会被过滤,其他的attrs或者string会继续被过滤。二是根据节点所在树结构中的关系查找其他节点:直接子节点:tag.childern和tag.contents是tag对象的两个属性,注意不是对应tag的属性!!!它们返回树结构中当前标记节点的直接子节点。tag.childern返回一个生成器tag.contents返回一个后代节点列表:tag.descendants返回一个生成器,遍历它可以得到当前tag节点的所有后代节点的循环遍历结果。直接父节点:tag.parent获取当前标签的直接父节点,所以父节点:tag.parents返回一个生成器,可以获取当前标签的所有父节点下一个兄弟节点:tag.next_sibling和tag.next_siblings,返回值类型不用多说。之前的兄弟节点:tag.previous_sibling和tag.previous_siblings,相同的返回类型不用赘述。以上大概就是BeautifulSoup在查找资料时需要的知识。其他的方法比如tag.find_parent(name,attrs,recursive,string,**kwargs)结合这两个方法,后面可以慢慢理解。