pytho爬虫
- 在大二来临前的暑假,因想要学习一点新的东西,并且想要获取一些图片、文章、视频之类的东西,于是就看上了
Python爬虫
来加强自己的知识技能,最开始问了一下度娘,上面介绍了一些爬虫框架和爬取准则,例如requests``re正则
等等,后来发现requests-html
更适合我,而且requests-html
和requests
出于同一个作者,提供了分页等新功能。所以这里总结一下自己的心得和小伙伴们分享下[在问度娘无果之后,我有寻找了很多文档和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
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
文件后,就对相应的内容进行爬取保存,结果如下:
结束语:
一个学期的通力合作,带来的是成功。一个说明书的编写完成,带来的是成就感。至此之际引用查尔斯・狄更斯的一句话:“我今日所做的事远比我往日的所作所为更好,更好;我今日将享受的安息远比我所知的一切更好,更好。”
声明:
好了,本文的内容就到这里了,但本文章用于笔记与分享个人学习的目的,非商业行为,代码为开源代码如有需要请注明出处。如果文章中有错误或者更好的建议可以与博主联系,谢谢铁铁们!!!