pytho爬虫


  • 在大二来临前的暑假,因想要学习一点新的东西,并且想要获取一些图片、文章、视频之类的东西,于是就看上了Python爬虫来加强自己的知识技能,最开始问了一下度娘,上面介绍了一些爬虫框架和爬取准则,例如requests``re正则等等,后来发现requests-html更适合我,而且requests-htmlrequests出于同一个作者,提供了分页等新功能。所以这里总结一下自己的心得和小伙伴们分享下[在问度娘无果之后,我有寻找了很多文档和UP博主的视频和博客自学爬虫,在不断的尝试与摸索中,逐渐掌握了这个爬虫库,自我感觉是比较简单的,所以来分享一下成绩,并写下笔记,接下来带小伙伴们一起学习。Let’s Go!]
  • 笔记主要是关于自己使用requests-html的一些常用语法用法总结。[我看了一下requests-html的中文文档,在哔哩哔哩中观看一些UP博主的教学视频,以及在CSDN简书中查看了些许同志的博客,在此感谢分享的UP博主们!]
  • 笔记由两部分内容构成: requests-html文档自学中的步骤分享[这里写笔记内容的构成]

作为一个真正的程序员,首先应该尊重编程,热爱你所写下的程序,他是你的伙伴,而不是工具。--------孔덕 흥[[每日三者吾身,帅否,富否,女朋友有否,滚去学习]


废话不多说,让我们来看下博客内容

《requests-html文档》


官方文档链接地址:

https://pypi.org/project/requests-html/

安装:

$pip install requests-html

只支持python3.6及以上

基本使用

这里我简单讲一下requests-html的使用,其中文文档已经给在上面了

获取网页

requests-html和其他解析HTML库最大的不同点在于HTML解析库一般都是专用的,所以我们需要用另一个HTTP库先把网页下载下来,然后传给那些HTML解析库。而requests-html自带了这个功能,所以在爬取网页等方面非常方便。
下面的代码获取了糗事百科上面的文字段子页面,返回的对象r是requests.Reponse类型,更确切的说是继承自前者的requests_html.HTMLResponse类型。这里其实和requests库的使用方法差不多,获取到的响应对象其实其实也没啥用,这里的关键就在于r.html这个属性,它会返回requests_html.HTML这个类型,它是整个requests_html库中最核心的一个类,负责对HTML进行解析。我们学习requests_html这个库,其实也就是学习这个HTML类的使用方法。
构造一个访问https://www.qiushibaike.com/text/的GET请求,使用Requests:

from requests_html import HTMLSession
session = HTMLSession()
r = session.get('https://www.qiushibaike.com/text/')
// 查看页面内容
print(r.html.html)

获取链接

links和absolute_links两个属性分别返回HTML对象(URL)所包含的所有链接和绝对链接(均不包含锚点)(已经自动去掉了html标签)。

# 获取链接
print(r.html.links)
print(r.html.absolute_links)

获取元素

request-html支持CSS选择器和XPATH两种语法来选取HTML元素。首先先来看看CSS选择器语法,它需要使用HTML的find函数,该函数有5个参数,作用如下:

  • selector,要用的CSS选择器;
  • clean,布尔值,如果为真会忽略HTML中style和script标签造成的影响(原文是sanitize,大概这么理解);
  • containing,如果设置该属性,会返回包含该属性文本的标签;
  • first,布尔值,如果为真会返回第一个元素,否则会返回满足条件的元素列表;
  • _encoding,编码格式。

例子:

# 首页菜单文本,通过css选择器选取一个Element对象
print(r.html.find('div#menu', first=True).text)
# 首页菜单元素
print(r.html.find('div#menu a'))
# 段子内容
print(list(map(lambda x: x.text, r.html.find('div.content span'))))

XPAT语法,需要另一个函数xpath的支持,它有4个参数:

  • selector,要用的XPATH选择器;
  • clean,布尔值,如果为真会忽略HTML中style和script标签造成的影响(原文是sanitize,大概这么理解);
  • first,布尔值,如果为真会返回第一个元素,否则会返回满足条件的元素列表;
  • _encoding,编码格式。

还是上面的例子,不过这次使用XPATH语法:

print(r.html.xpath("//div[@id='menu']", first=True).text)
print(r.html.xpath("//div[@id='menu']/a"))
print(r.html.xpath("//div[@class='content']/span/text()"))

输出和上面那个几乎一样,之所以说是“几乎”,因为第三个输出会多出几个换行符,不知道什么原因。需要注意的一点是如果XPATH中包含text()或@href这样的子属性,那么结果相应的会变成简单的字符串类型,而不是HTML元素。

元素内容

糗事百科首页LOGO的HTML代码如下所示:

<div class="logo" id="hd_logo">
<a href="/"><h1>糗事百科</h1></a>
</div>

我们来选取这个元素:

e = r.html.find("div#hd_logo", first=True)

要获取元素的文本内容,用text属性:

print(e.text)
# 糗事百科

要获取元素的attribute,用attr属性:

print(e.attrs)
# 输出为: {'class': ('title',)}

获取元素的html代码

print(e.html) 
# 输出为: <div class="title"> <a class="name" href="/u/18d731821bfc">还是那个没头脑</a> </div>

要搜索元素的文本内容,用search函数

print(e.search('还是{}没头脑')[0]) 
# 输出为: 那个

两个链接属性

print(e.links) # 相对路径 
print(e.absolute_links) # 绝对路径

JavaScript支持

有些网站是使用JavaScript渲染的,这样的网站爬取到的结果只有一堆JS代码,这样的网站requests-html也可以处理,关键一步就是在HTML结果上调用一下render函数,它会在用户目录(默认是~/.pyppeteer/)中下载一个chromium,然后用它来执行JS代码.
载过程只在第一次执行,以后就可以直接使用chromium来执行了。唯一缺点就是chromium下载实在太慢了。

h = session.get('http://python-requests.org/') 
h.html.render()
r.html.search('Python 2 will retire in only {months} months!')['months'] '<time>25</time>'

render函数还有一些参数,顺便介绍一下(这些参数有的还有默认值,直接看源代码方法参数列表即可):

  • retries: 加载页面失败的次数
  • script: 页面上需要执行的JS脚本(可选)
  • wait: 加载页面钱的等待时间(秒),防止超时(可选)
  • scrolldown: 页面向下滚动的次数
  • sleep: 在页面初次渲染之后的等待时间
  • reload: 如果为假,那么页面不会从浏览器中加载,而是从内存中加载
  • keep_page: 如果为真,允许你用r.html.page访问页面

比如说简书的用户页面上用户的文章列表就是一个异步加载的例子,初始只显示最近几篇文章,如果想爬取所有文章,就需要使用scrolldown配合sleep参数模拟下滑页面,促使JS代码加载所有文章。

智能分页

rq = session.get("https://reddit.com") 
for html in rq.html:
	print(html)

直接使用HTML

前面介绍的都是通过网络请求HTML内容,其实requests-html当然可以直接使用,只需要直接构造HTML对象即可:

from requests_html 
import HTML doc = "<a href='https://httpbin.org'>" 
html = HTML(html=doc) 
print(html.links) {'https://httpbin.org'}

直接渲染JS代码

script = """ 
	() => { 
		return { 
			width: document.documentElement.clientWidth, height: document.documentElement.clientHeight, deviceScaleFactor: window.devicePixelRatio, 
				} 
			} 
		""" 
val= html.render(script=script,reload=False) 
print(val) print(html.html)

自定义请求

前面都是简单的用GET方法获取请求,如果需要登录等比较复杂的过程,就不能用get方法了。
HTMLSession类包含了丰富的方法,可以帮助我们完成需求。下面介绍一下这些方法。

自定义用户代理

有些网站会使用UA来识别客户端类型,有时候需要伪造UA来实现某些操作。
如果查看文档的话会发现HTMLSession上的很多请求方法都有一个额外的参数**kwargs,这个参数用来向底层的请求传递额外参数。
我们先向网站发送一个请求,看看返回的网站信息。

from pprint import pprint # 提供了可以按照某个格式正确的显示python已知类型数据的一种方法 
import json 
pp_r = session.get('http://httpbin.org/get') 
pprint(json.loads(pp_r.html.html))

返回的结果如下:

{'args': {}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) ' 'AppleWebKit/603.3.8 (KHTML, like Gecko) ' 'Version/10.1.2 Safari/603.3.8'}, 'origin': '150.95.184.46, 150.95.184.46', 'url': 'https://httpbin.org/get'}

UA是requests-html自带的UA,下面换一个UA:

ua = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0' 
ppp_r = session.get('http://httpbin.org/get',headers={'user-agent': ua}) 
pprint(json.loads(ppp_r.html.html))

看到UA确实发生了变化:

{'args': {}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Host': 'httpbin.org', 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) ' 'Gecko/20100101 Firefox/62.0'}, 'origin': '150.95.184.46, 150.95.184.46', 'url': 'https://httpbin.org/get'}

有需要可以在header中修改其他参数。

模拟表单登陆

HTMLSession带了一整套的HTTP方法,包括get、post、delete等,对应HTTP中各个方法。比如下面我们就来模拟一下表单登录
表单登陆

r = session.post('http://httpbin.org/post', data={'username': 'python', 'passwd': 123456}) 
pprint(json.loads(r.html.html))

可以看到forms中确实收到了提交的表单值:

{'args': {}, 'data': '', 'files': {}, 'form': {'passwd': '123456', 'username': 'python'}, 'headers': {'Accept': '*/*', 'Accept-Encoding': 'gzip, deflate', 'Content-Length': '29', 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'httpbin.org', 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) ' 'AppleWebKit/603.3.8 (KHTML, like Gecko) ' 'Version/10.1.2 Safari/603.3.8'}, 'json': None, 'origin': '150.95.184.46, 150.95.184.46', 'url': 'https://httpbin.org/post'}

好了,基本使用就先介绍到这里,不懂的可以去https://pypi.org/project/requests-html/康康哦,官方文档里面的更明了清晰。
下面就开是我们自己的爬取吧!

《自学中的步骤分享》


编者自学爬虫三步走:

我的文档结构如下,你们也可以做出相应的改动,我是为了我更好的创作的学习对他分文件和分类,方便调用

+-- main.py
+-- html_res
|   +-- Get_res.py
+-- html_renders
|   +-- Renders.py
+-- html_download
|   +-- Download.py

我想要一些学习文档,于是从http://www.feiguyunai.com/python交流网站中爬取并保存到本地txt中

交流网站

1. 发送请求获取网页HTML

python基础网页

html_res//Get_res.py

import random
from pprint import pprint
from requests_html import HTMLSession

class html_res(object):
    def __init__(self,post_url,path):
        self.post_url = post_url
        self.path = path
    def get_res(self):
        '''
        获取并查看网页
        '''
        session = HTMLSession()
        # 可以在发送请求的时候更换user-agent
        users = {
                1 : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:62.0) Gecko/20100101 Firefox/62.0',
                2 : 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_6_8; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
                3 : 'Mozilla/5.0 (Windows; U; Windows NT 6.1; en-us) AppleWebKit/534.50 (KHTML, like Gecko) Version/5.1 Safari/534.50',
                4 : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_0) AppleWebKit/535.11 (KHTML, like Gecko) Chrome/17.0.963.56 Safari/535.11'
                }
        ur1 = random.sample(users.keys(),1)
        ur = "users"+str(ur1)
        # print(ur)
        res = session.get(self.post_url, headers={'user-agent': ur})
        print("网页状态",res)
        # 查看页面结构
        # print(res.html.html)
        return res

2. 解释网页HTML,得到链接、数据或连接等

网页结构

这段代码我放在了和get_res在同一个class中,因为后期不会有太大改动
html_res//Get_res.py

def paths(self,r):
    '''
    获取网页中的链接
    r:网页res
    path:所有路径:"All_paths"/绝对路径:"Absolute_path"
    '''
    if self.path =="All_paths":
        print("网页所有链接:")
        pprint(r.html.links)
    elif self.path == "Absolute_path":
        print("网页绝对链接:")
        pprint(r.html.absolute_links)

3. 下载或保存数据

html_renders\\Renders

def download(texts,file_name):
	file_paths = file_path + "\\" + file_name
	with open(file_paths,'a',encoding="utf-8") as f:#使用追加模式写入文件
		f.write(texts)
		f.close()

4. 现有的资料基本上都是每一步用一个库。

这里是main.py中的代码,也是主体代码

import os
file_path = os.path.abspath(os.path.dirname(__file__))
from html_res.Get_res import html_res
from html_renders.Renders import renders
from html_download.Download import download

def clear(r):
    '''
    数据清洗
    '''
    tags = r.html.find("div.entry-content")
    print(tags)
    for tag in tags:
        texts = (tag.text)
        print(texts)
        download(texts,"python基础.txt")
    print("已经获取成功!!")


if __name__ == '__main__':
    url = 'http://www.feiguyunai.com/index.php/2017/08/11/pythonbase01/'
    g = html_res(url,'Absolute_path')
    r = g.get_res()
    g.paths(r)
    renders(r)
    c = clear(r)

运行main.py文件后,就对相应的内容进行爬取保存,结果如下:

爬取结果

结束语:


一个学期的通力合作,带来的是成功。一个说明书的编写完成,带来的是成就感。至此之际引用查尔斯・狄更斯的一句话:“我今日所做的事远比我往日的所作所为更好,更好;我今日将享受的安息远比我所知的一切更好,更好。”

声明:

好了,本文的内容就到这里了,但本文章用于笔记与分享个人学习的目的,非商业行为,代码为开源代码如有需要请注明出处。如果文章中有错误或者更好的建议可以与博主联系,谢谢铁铁们!!!

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐