应朋友要求,给他写一篇关于爬虫的博客,翻翻找找,找到了以前写的爬虫里表现得比较好的,拿出来给大家讲讲。
什么是爬虫
先从百度百科上对爬虫的定义开始吧:
网络爬虫是一种按照一定的规则,自动地抓取万维网信息的程序或者脚本
这篇博客,我们就做个简单的定向爬虫,先来看看爬虫工作的流程:
首先是计算机通过要爬取的网页的url对网页发送请求,网页接收到请求后在没有问题的情况下会接受请求并返回响应,返回的响应会携带网页的html源码。获取到html文本后就是我们这篇博客编写的爬虫需要做的最主要的任务——解析网页并将它保存。
想要看更详细的,可以参考大佬的博客爬虫系列(一) 网络爬虫简介
编写爬虫要用的库
接下来我们介绍编写爬虫要用到的库,我这里就简单介绍一下requests库和我比较喜欢的re库:
requests库
原文:
requests库
安装requests库可以命令行输入:
pip install requests
request对象常用的请求方法:
- request 其他六个方法,底层调用该方法
- get 从服务器获取资源
- post 将资源提交到服务(不可覆盖)
- put 修改服务器资源(可覆盖)
- head 获取服务器资源的部分信息
- patch 修改服务器资源(可部分覆盖)
- delete 删除服务器资源
当然我们后面用到的只有get()方法
然后是请求常用的几个可选参数:
- timeout 设置超时(单位:秒)imeout = 30
- params get请求携带的参数
- data post请求携带的参数
- headers 请求头参数 headers = {“User-Agent”: “Mozilla/5.0”}
- files 上传文件files= {“files”:open(“git.jpeg”,“rb”)}
- proxies 服务器代理,模拟真实的主机proxies={“http”:“http://user:password@127.0.0.1:9999”,“https”:“http://127.0.0.1:8888”}
- auth 认证auth=(“user”,“123”)
当然,我写代码并没有用到这些,但并不代表他们不重要。
最后是request常用的几个属性:
import requests
def common_attributes():
url = "https://www.baidu.com/"
r = requests.get(url)
print(r.raise_for_status) # 状态码
print(r.encoding) # 字符编码吗,header中content-type中的值
print(r.apparent_encoding) # 实际文档编码,更具文档分析出来的编码
print(r.headers) # response头
print(r.text) # 服务器返回的文本
print(r.content) # 返回的内容的二进制
print(r.cookies) # 返回的cookies
print(r.request.headers) # 请求头
print(r.request.url) # 请求url
r.text中包含的就是我们要进行解析的html文本。
re库
这里介绍re库并不是说它是最简单的,只是我自己在用的过程中实在是没有很理解beautifulsoup的使用,经常出错,所以我写爬虫的时候常用re。并且如果要深入爬虫的话,re库是必须要学会用的。
re库,即正则表达式库,熟悉正则表达式的同学肯定能很快上手,不熟悉的就得好好补补了,毕竟这是比较重要的无论是在python还是一些其他的编程语言。
原文:Python的Re库(正则表达式)基本用法
介绍常用的几个功能函数:
这些功能函数的参数有需要的可以自己去查询,我说说下面要用的:
1、re.search(pattern,string,flags=0)
在一个字符串中搜索匹配正则表达式的第一个位置,返回match对象
pattern:正则表达式的字符串或原生字符串表示
string:待匹配的字符串
flags:正则表达式使用时的控制标记
2、re.findall(pattern,string,flags=0)
搜索字符串,以列表类型返回全部能匹配的字串
pattern:正则表达式的字符串或原生字符串表示
string:待匹配的字符串
flags:正则表达式使用时的控制标记
什么是flags控制标记呢:
这里先不解释,因为我们下面用不到,但你要爬小说的话,一定会用到的!
开始做爬虫吧
那么接下来我们开始吧。
我下面要爬的是一个桌面壁纸网站的壁纸,先看看这个网站:
url网址:
http://www.netbian.com/sitemap/index.htm
我们要爬取的就是资源列表里的这些,我选的这个网站是文字的,点击后才会看到壁纸图片,方便爬取。我们可以先自己试试点击壁纸,然后下载等等等等。其实爬虫也就是模仿我们使用浏览器点击、阅读的过程,自己走了一遍流程,就能够明白爬虫该怎么编写了!!!
接下来上代码:
爬虫代码
# -*- coding: utf-8 -*-
"""
Created time: 2020/2/6 14:20
爬取桌面壁纸(图片)
@author: 沧海云帆
"""
import requests
import os
import re
def geturl(url):
'''
获取主网页上各个图片所在网页
'''
a = 'http://www.netbian.com'#获取图片的尾地址后添加前缀
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
except:
print('error')
list0 = []
list0 = re.findall(r'<a href="/desk/\d{5}.htm" target="_blank">',r.text)
list1 = []
for i in list0:
list1.append(a + i[9:24])#切片获取地址
return list1#返回带有图片地址的列表
def getpurl(url):
'''
获得图片的下载链接
'''
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
except:
print('error')
match = re.search('<img src="http://img.netbian.com/file/.*?\.jpg" alt',r.text)#搜索下载链接
picurl = match.group(0)
picurl = picurl.split('"')[1]
return picurl#返回下载链接
def writetojpg(url):
'''
保存图片
'''
root = "D:/pic/"#存储目录
path = root + url.split('/')[-1]
try:
if not os.path.exists(root):
os.mkdir(root)
if not os.path.exists(path):
r = requests.get(url)
with open(path,'wb') as f:
f.write(r.content)#写入文件,即下载
f.close()
else:
print("文件已经存在!")
except:
print("爬取失败!")
def main():
'''
主程序
'''
print("开始")
url_1 = "http://www.netbian.com/sitemap/index.htm"
list1 = geturl(url_1)
for j in list1:
picurl = getpurl(j)
writetojpg(picurl)
print("1/10 成功")
for i in range(2,10):
try:
list2 = geturl("http://www.netbian.com/sitemap/index_%s.htm" % str(i))
for j in list2:
picurl = getpurl(j)
writetojpg(picurl)
print("%s/10 成功" % str(i))
except:
print("失败")
continue
print("结束")
if __name__ == "__main__":
main()
这是我蛮早之前写的代码,今天重新翻出来封装了一下,没有什么注释,看起来不太舒适,接下来我来慢慢讲。
首先我们直接看主函数main()来理解流程:
def main():
'''
主程序
'''
print("开始")
url_1 = "http://www.netbian.com/sitemap/index.htm"
list1 = geturl(url_1)
for j in list1:
picurl = getpurl(j)
writetojpg(picurl)
print("1/10 成功")
for i in range(2,10):
try:
list2 = geturl("http://www.netbian.com/sitemap/index_%s.htm" % str(i))
for j in list2:
picurl = getpurl(j)
writetojpg(picurl)
print("%s/10 成功" % str(i))
except:
print("失败")
continue
print("结束")
url_1 就是我们要爬取的那个网站的网址,因为首页的url的index后没有后缀,所以需要把首页爬取过程放到循环外面,而其他的页面都有index_2,index_3样的就可以直接做个循环来爬取。
循环里做的任务就比较容易理解了:geturl()获取到各个网页上的壁纸的url链接;getpurl()获取到壁纸的下载链接;writetojpg()将图片保存。
接下来我们看看这几个函数是怎么实现的:
def geturl(url):
'''
获取主网页上各个图片所在网页
'''
a = 'http://www.netbian.com'#获取图片的尾地址后添加前缀
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
except:
print('error')
list0 = []
list0 = re.findall(r'<a href="/desk/\d{5}.htm" target="_blank">',r.text)
list1 = []
for i in list0:
list1.append(a + i[9:24])#切片获取地址
return list1#返回带有图片地址的列表
r.raise_for_status()在这里并没有发挥多大的作用,只是在测试的时候需要用到,我就懒得删了,如果得到响应,它的返回值应该是200;
r.encoding = r.apparent_encoding这行代码只要是为了统一编码,有时候,爬虫识别的编码不正确会导致得到的是乱码;
re.findall()会返回一个列表,代码里的第一个参数就是正则表达式字符串,其实实际发挥作用的只有\d{5}表示五个数字,然后就是切片获取图片地址了,没啥好说的。
def getpurl(url):
'''
获得图片的下载链接
'''
try:
r = requests.get(url)
r.raise_for_status()
r.encoding = r.apparent_encoding
except:
print('error')
match = re.search('<img src="http://img.netbian.com/file/.*?\.jpg" alt',r.text)#搜索下载链接
picurl = match.group(0)
picurl = picurl.split('"')[1]
return picurl#返回下载链接
和上面一样的开头,但是这里并没有用re.findall(),而是使用了re.search(),它将匹配正则字符串并返回第一个匹配成功的(以match对象的方式),实际起作用的是正则字符串中实际起作用的是(.*?),匹配任意字符串;
match.group(0)返回的就是匹配到的字符串;下面那行是拆分并获取下载地址。
def writetojpg(url):
'''
保存图片
'''
root = "D:/pic/"#存储目录
path = root + url.split('/')[-1]
try:
if not os.path.exists(root):
os.mkdir(root)
if not os.path.exists(path):
r = requests.get(url)
with open(path,'wb') as f:
f.write(r.content)#写入文件,即下载
f.close()
else:
print("文件已经存在!")
except:
print("爬取失败!")
这个函数就没有什么好讲的了,就是通过获取到的下载链接,访问下载,我这里是写入到了D盘下的pic文件夹。
运行截图:
整个爬虫会爬取十个页面大概一百七十多张壁纸。
爬虫是我在慕课上跟着嵩天老师的慕课学的,有兴趣多学一些的可以去看看。