首先来说下什么是爬虫,按照百度百科的说法是:是一种按照一定规则,自动抓取万维网信息的程序或者脚本;首先它是程序,需要我们定义好规则,然后程序就会按照定义好的规则抓取网络上的信息,数据抓取下来了之后,需要我们对这个庞大的数据进行筛选、提取,也就是我们通常说的数据清洗,获得我们需要的信息。这里需要说的一点是,爬虫并不是python的专利,用其他的语言也是可以做到的,只是因为python提供了很多方便我们工作的库,可以极大的降低我们开发的难度,所以使用python开发爬虫非常多。
好了,我们简单的讲一下什么是爬虫:爬虫其实就是模拟了我们打开网页,获取网络信息的这一过程,只是他不用把过程显示出来,他默默完成这些工作,按照我们定义的规则,将打开的页面中特定的信息存储起来供我们使用。
使用python爬取信息,我们可以使用的工具和框架非常多,后面我们慢慢的学习;首先先来看一下,最简单的文字的提取,找到一个古诗文网站,网站的结构相较简单,可以帮助对爬虫这一概念很快的理解。
使用工具及环境:
先来分析下我们需要在古诗文网站获取李白的全部古诗,需要做哪几步?
https://so.gushiwen.org/authors/authorvsw_b90660e3e492A1.aspx # 李白诗文第一页
https://so.gushiwen.org/authors/authorvsw_b90660e3e492A2.aspx # 李白诗文第二页
https://so.gushiwen.org/authors/authorvsw_b90660e3e492A3.aspx # 李白诗文第三页
……
我们发现网址是有规律的,只是最后一位有变化,那么我们是不是可以循环执行一百次,将网址重新拼接,访问,在提取内容;
这个仅限于有规律的网站,如果没有规律的话,我们发现一般网站最下面都有下一页,我们可以获取下一页的网址,然后访问,也是一样的。
好了,说的这么多,现在我们用代码来说明:
import requests # requests就是我们用来请求网页的库
# 如果没有用 pip install requests 安装
url = 'https://so.gushiwen.org/authors/authorvsw_b90660e3e492A1.aspx' # 访问的网址
result = requests.get(url) # 对目标网址发出请求
print(result) # 我们将访问的结果输出,看看返回了什么
print(result.status_code) # 打印状态码
print(result.url) # 打印请求url
print(result.headers) # 打印头信息
print(result.cookies) # 打印cookie信息
print(result.text) # 以文本形式打印网页源码
print(result.content) # 以字节流形式打印
# 输出结果:
# # 返回的就是响应的结果,200即为访问成功
# 200
# https://so.gushiwen.org/authors/authorvsw_b90660e3e492A1.aspx
# {'Server': 'Tengine', 'Content-Type': 'text/html; charset=utf-8', 'Transfer-Encoding': 'chunked', 'Connection': 'keep-alive', 'Vary': 'Accept-Encoding, *', 'Cache-Control': 'public', 'Expires': 'Mon, 09 Dec 2019 12:17:34 GMT', 'X-AspNet-Version': '4.0.30319', 'X-Powered-By': 'UrlRewriter.NET 1.7.0, ASP.NET', 'Date': 'Mon, 09 Dec 2019 00:48:37 GMT', 'Ali-Swift-Global-Savetime': '1575852517', 'Via': 'cache23.l2cn1827[0,200-0,H], cache7.l2cn1827[2,0], cache9.cn1447[0,200-0,H], cache3.cn1447[1,0]', 'Age': '30454', 'X-Cache': 'HIT TCP_MEM_HIT dirn:6:387273622', 'X-Swift-SaveTime': 'Mon, 09 Dec 2019 01:52:45 GMT', 'X-Swift-CacheTime': '37489', 'Timing-Allow-Origin': '*', 'EagleId': '6f034f9715758829713824707e', 'Content-Encoding': 'gzip'}
#
# 最后面两项太长了,这里就不显示了
ok,什么状态码、头信息、cookie不清楚是什么,不用管,我们目前用不到,后面会详细讲的,但是有一个,我们最后是不是从源码分析的,所以我们需要返回页面的源码
现在我们源码也有了,怎么找出我们需要内容呢?
我们文本匹配的方式很多,因为我们需要的内容都是标签的值,正则表达式在这种情况下不好匹配,所以我们选用xpath进行内容的提取,如果这一部分不了解的话,可以百度或看我的另一篇博文;
data = html.xpath('//div[@class="sons"]') # 根据源码分析,我们发现所有的诗文信息都是在里面的
# 所以我们先把所有的找出来
for d in data:
title = d.xpath('./div[@class="cont"]/p/a/b/text()') # 一层一层找,题目在这里
author = d.xpath('./div[@class="cont"]/p[@class="source"]/a/text()') # 朝代和作者
sw_all = '' # 最后将诗文拼接成字符串
sw = (d.xpath('./div[@class="cont"]/div/text()')) # 先将诗文所有的行全部获取下来
for s in sw: # 遍历所有的行
if s != '\n': # 我们发现会有很多空行产生,这个是我们不需要的
if s[0] == '\n': # 还有些在开头的时候会有一个换行
sw_all += s[1:] # 我们需要将换行符屏蔽掉,注意换行符是一个字符
else:
sw_all += s # 将其拼接在一起
sw_all += '\n' # 在每一行后面都加上一个换行符,这样所有的语句就不会都在一行上面
if sw_all == '': # 还有一种情况是,较短的诗文,里面还有一层标签,那么上面的循环就会全部过滤掉了
sw = (d.xpath('./div[@class="cont"]/div/p/text()')) # 重新匹配
for s in sw: # 跟上面的操作是一样的
if s != '\n':
if s[0] == '\n':
sw_all += s[1:]
else:
sw_all += s
sw_all += '\n'
现在我们已经可以匹配到所有的诗文信息了,接下来就是将诗文保存起来:
try: # 异常处理
# 这里先提前创建好了文件夹,需要注意点的是:有些题目中间有 '/' 分隔,最后合成文件名就会变成路径的一部分
# 这肯定是有问题的,所以我们需要将题目中的 '/' 替换掉
with open('./李白/{}({}).txt'.format(title[0].replace('/',' '),author[1]),'w') as f:
f.write(title[0]+'\n'+author[0]+' '+author[1]+'\n'+sw_all) # 将内容写入
except:
print('{}下载失败!'.format(title[0])) # 如果出现异常情况,提示那首诗文出现了问题
下面看一下全部的代码:
import requests
from lxml import etree
url = 'https://so.gushiwen.org/authors/authorvsw_b90660e3e492A1.aspx'
result = requests.get(url).text
html = etree.HTML(result)
data = html.xpath('//div[@class="sons"]')
for d in data:
title = d.xpath('./div[@class="cont"]/p/a/b/text()')
author = d.xpath('./div[@class="cont"]/p[@class="source"]/a/text()')
sw_all = ''
sw = (d.xpath('./div[@class="cont"]/div/text()'))
for s in sw:
if s != '\n':
if s[0] == '\n':
sw_all += s[1:]
else:
sw_all += s
sw_all += '\n'
if sw_all == '':
sw = (d.xpath('./div[@class="cont"]/div/p/text()'))
for s in sw:
if s != '\n':
if s[0] == '\n':
sw_all += s[1:]
else:
sw_all += s
sw_all += '\n'
try:
with open('./李白/{}({}).txt'.format(title[0].replace('/',' '),author[1]),'w') as f:
f.write(title[0]+'\n'+author[0]+' '+author[1]+'\n'+sw_all)
except:
print('{}下载失败!'.format(title[0]))
好了,现在还有最后一个问题,我们现在只是下载了一个页面的文章,如何获取所有的诗文呢?
我们这里直接采用最暴力的方法,直接凭借访问地址:
import requests
from lxml import etree
for n in range(1,101): # 从第1页到第100页
try: # 这里加上异常处理非常关键,如果页面出错,不会终止程序
url = 'https://so.gushiwen.org/authors/authorvsw_b90660e3e492A{}.aspx'.format(str(n)) # 拼接访问地址
result = requests.get(url).text
html = etree.HTML(result)
data = html.xpath('//div[@class="sons"]')
for d in data:
title = d.xpath('./div[@class="cont"]/p/a/b/text()')
author = d.xpath('./div[@class="cont"]/p[@class="source"]/a/text()')
sw_all = ''
sw = (d.xpath('./div[@class="cont"]/div/text()'))
for s in sw:
if s != '\n':
if s[0] == '\n':
sw_all += s[1:]
else:
sw_all += s
sw_all += '\n'
if sw_all == '':
sw = (d.xpath('./div[@class="cont"]/div/p/text()'))
for s in sw:
if s != '\n':
if s[0] == '\n':
sw_all += s[1:]
else:
sw_all += s
sw_all += '\n'
try:
with open('./李白/{}({}).txt'.format(title[0].replace('/',' '),author[1]),'w') as f:
f.write(title[0]+'\n'+author[0]+' '+author[1]+'\n'+sw_all)
except:
print('{}下载失败!'.format(title[0]))
except:
print('第{}页下载失败'.format(n))
确实可以下载,但是只有100首,按理一个页面是10首,100个页面应该是1000首才对,找一下问题,我们看下第十一页:
惊奇的发现,竟然十页之后的内容,要我们用客户端才能访问,真是不想再说什么了;好了,这就是最简单的文本爬取的方法,有疑问或者没有讲清楚的,可以在下面留言哈!