@ 我的老师:Jack Cui
PS:我是通过 看 Jack Cui 老师的文章 学习的爬虫,也为我之后的 爬虫打开了大门。
通常我们学习爬虫,都感觉是一个 很难的事儿。但实际不然。爬虫 无非就是要 爬取 四样有用的 东西!
| 文字 | 图片 | 音乐 | 视频 |
|---|
那么这一节,我们就要 去网络上下载一篇小说。即 文字 的爬取。
2.1.1 爬虫基本步骤
① URL
URL:https://www.yingsx.com/
② 发送请求
我们需要先 明确如何发起 HTTP 请求,获取到 数据。而暂时我们 能够接触到的 请求类型就是 GET (即通过显露的 URL 和 相关参数 来进行 目的资源和目的数据的 直接获取)
③ 解析数据 <今天的重点>
当我们访问了 目的资源 后,我们就可以拿到源代码,在这个源代码里。我们就能 提取 出 我们想要的数据。
④ 保存数据
将我们想要的数据保存下来,保存到文件 中。是我们 刚接触爬虫 最常用的手段。这样我们 在用到某些数据的时候,通过 文件的读取 即可。
解析数据 有很多种方式:
① 字符串的解析 (通过自身的 逻辑经验,代码能力,可以配合 一些原生态的 字符串方法 来实现 目的数据的提取)【难度: ⭐⭐⭐⭐ 】
② 正则表达式 (正则表达式 大家应该都知道,它通常用来 匹配相应的字符串。) 若不知道的同学,可以 点击这篇文章学习一下:< 程序员必备知识 01 正则表达式 >
③ 解析数据的模块 (虽然模块千千多!但这里建议大家使用 xpath、BeautifulSoup 这两者)+ re 正则模块,就可以很好的 起到 解析数据的效果。【难度: ⭐⭐ 】
2.1.2 Beautiful Soup
① 安装 Beautiful Soup
pip install beautifulsoup4
PS:这里建议大家 跟着 我的教程走,慢慢找感觉,你会发现 学习编程,没有什么比 直接敲代码实践 来得轻松,来得快了。
② 安装 lxml (以 lxml 方式来进行解析)
pip install lxml
我们先来看下 这个 URL:https://www.yingsx.com/0_100/
右键 检查,你会在 上面的 工具栏里,看到 一个 小鼠标,点击这个小鼠标,再对你感兴趣的 数据进行 点击。你会发现 它自动的 将 该数据在源代码中的位置 跳转显现了出来。
而这张图,我们又可以知道。我们 每一章节 都有一个 URL。
这些 URL 都在 描述列表or自定义列表 的 <dd> URL <\dd> 标签中。
那么 我们 就先 教 大家 利用 Beatiful Soup 模块 来进行 这些 URL 的爬取。
2.2.2 爬取 每一章 的 URL
① 先来看下 我们最基本的 源代码是否能爬取成功。
import requests
# get 方式访问 URL
req = requests.request(method="GET",url = "https://www.yingsx.com/0_100/")
# 编码调节为 UTF-8
req.encoding = 'utf-8'
print(req.text)
② 利用 BeautifulSoup 进行 lxml 的解析。
--> 并通过 bs.find() 先找到 list 这个 div 大框,因为在它的内部 才有 那些个 dd
--> 再根据 获取到 list div 元素,find_all('dt')[1] 找到 第二个 dt 标签,因为我们可以清楚的看到,真正的所有 URL 都在 第二个标签的后面。
--> 然后 我们 让 dt = find_all('dt')[1] 再 dt.find_all_next('dd') 就可以获取到 之后的所有 dd 标签了。
--> 最后 我们 再根据 每个 dd 来 find('a') 里面的 每个 a 标签。
import requests
from bs4 import BeautifulSoup
# get 方式访问 URL
URL = "https://www.yingsx.com/0_100/"
req = requests.request(method="GET",url=URL)
# 编码调节为 UTF-8
req.encoding = 'utf-8'
#print(html)
html = req.text
# 以lxml 方式进行解析
bs = BeautifulSoup(html,'lxml')
# 我们要获取的标签是 div,而这个 div 的 标识 是 id = 'list'
list = bs.find("div",)
# 通过 这个 div 获取到 内部的 第二个 dt
dt = list.find_all('dt')[1]
# a 标签 列表
aList = []
# url 列表
urlList = []
# name 文章名 列表
nameList = []
# dt.find_all_next('dd') 找到 第二个 dt 标签后 所有的 dd 返回一个 列表
for dd in dt.find_all_next('dd'):
# 获取每个 dd 标签 内部的 a 标签
aList.append(dd.find('a'))
# 获取每个 a 标签 的 href 属性值,即 每一章 的 url
urlList.append('https://www.yingsx.com'+ dd.find('a').get('href'))
# 获取每个 a 标签 的 内容,即 每一章 的 标题名
nameList.append(dd.find('a').text)
for url in urlList:
print(url)
BeautifulSoup(待分析的字符串源码,分析的格式or方式) 提供一个待分析的字符串,和 分析的格式或方式,我们就会 得到一个 bs对象。该对象 的数据结构 是一棵树,当然我们也不需进行细节的刨析。我们只要知道 我们拿到这个对象,就相当于 拿到了 你提供的源代码的解析器。
bs.find(元素标签的名称,定位标识) 我们可以通过 某些定位标识,比如 它的 独有属性 id ,或者 class 等 来确认 它是哪一个 元素。
bs.find_all(元素标签的名称,定位的标识) 它是 在 定位标识 ok 的情况下,当然一般 这个方法 不会写 定位标识。它会把 所有符合的标签,都获取出来,并且 存储到一个 列表里。
dt.find_all_next(元素标签的名称,定位的标识) 它是 在 当前这个元素的基础上,往下 再去探索 所有的 符合标识的 标签。
元素标签.text 能够直接获取到 标签内 写的 大白话文字。比如我们这次获取 到的 就是 每一章的名字!
元素标签.get('属性名') 通过属性名 获取到该元素 对应的属性值。
2.2.2 爬取 每一章 的 小说内容
接下来,我们就要 对 每一个文章 的 页面内容和源代码 进行 分析。
我们会发现呢,每一章的内容 其实都 在 <div ></div> 标签里。
所以我们同理,依靠 上面的 步骤和教程。可以很轻松的 得到 这个内容。
但是问题来了
① 我们获取到的内容,有 这个特殊标识符,在 html 里面,代表 空格。但是 我们 如果 是字符串的话。空格 就是 空格呀 ~ ~ 哪还有这个   所以我们要把 它 替换为 空格
content = content.text.strip().split('\xa0' * 4,' ')
其实上面这行代码是一个简化版。看下面的代码就知道了!
content = content.text.split('\xa0' * 4)
for i,x in enumerate(content):
content[i] = x .strip()
PS:已有网友 提醒,其实没必要 进行替换,读取出来 后,就是 四个空格。哈哈 ~ 我当时 写的很急促。这个代码…… 大意了!没闪 ~
② 我们肯定是要 写 到文件里的,要不然 我们爬虫的意义何在。
用最 python 自带的,也是最简单的 文件操作即可解决该问题 ……
我们先 根据我们的 思路 写一章 看看吧!!!
import requests
from bs4 import BeautifulSoup
import os
# get 方式访问 URL
URL = "https://www.yingsx.com/0_100/"
req = requests.request(method="GET",url=URL)
# 编码调节为 UTF-8
req.encoding = 'utf-8'
#print(html)
html = req.text
# 以lxml 方式进行解析
bs = BeautifulSoup(html,'lxml')
# 我们要获取的标签是 div,而这个 div 的 标识 是 id = 'list'
list = bs.find("div",)
# 通过 这个 div 获取到 内部的 第二个 dt
dt = list.find_all('dt')[1]
# a 标签 列表
aList = []
# url 列表
urlList = []
# name 文章名 列表
nameList = []
# dt.find_all_next('dd') 找到 第二个 dt 标签后 所有的 dd 返回一个 列表
for dd in dt.find_all_next('dd'):
# 获取每个 dd 标签 内部的 a 标签
aList.append(dd.find('a'))
# 获取每个 a 标签 的 href 属性值,即 每一章 的 url
urlList.append('https://www.yingsx.com'+ dd.find('a').get('href'))
# 获取每个 a 标签 的 内容,即 每一章 的 标题名
nameList.append(dd.find('a').text + '.txt')
os.mkdir('元尊')
for i,url in enumerate(urlList):
req = requests.request(method="GET",url = url)
req.encoding = 'utf-8'
html = req.text
bs = BeautifulSoup(html,'lxml')
# 找到 content div 标签
content = bs.find("div",)
content = content.text.strip().split('\xa0' * 4)
f = open('元尊\\'+ nameList[i], 'w')
for str in content:
f.write(str)
f.close()
break
此时我们 又会 犯一个 细节的错误,编码问题!我们知道 我们这个是 中文的小说。所以 写入文件的时候,肯定编码 要 为 utf-8 呀!
2.3.1 tqdm 进度条模块 和 成品代码
为了美观,我们最后还是决定 要加一个 下载的进度条。
这里 推荐 大家用 tqdm
-------------------------------------------------成品 代码---------------------------------------------------
import requests
from bs4 import BeautifulSoup
import os
from tqdm import tqdm
# get 方式访问 URL
URL = "https://www.yingsx.com/0_100/"
req = requests.request(method="GET",url=URL)
# 编码调节为 UTF-8
req.encoding = 'utf-8'
#print(html)
html = req.text
# 以lxml 方式进行解析
bs = BeautifulSoup(html,'lxml')
# 我们要获取的标签是 div,而这个 div 的 标识 是 id = 'list'
list = bs.find("div",)
# 通过 这个 div 获取到 内部的 第二个 dt
dt = list.find_all('dt')[1]
# a 标签 列表
aList = []
# url 列表
urlList = []
# name 文章名 列表
nameList = []
# dt.find_all_next('dd') 找到 第二个 dt 标签后 所有的 dd 返回一个 列表
for dd in dt.find_all_next('dd'):
# 获取每个 dd 标签 内部的 a 标签
aList.append(dd.find('a'))
# 获取每个 a 标签 的 href 属性值,即 每一章 的 url
urlList.append('https://www.yingsx.com'+ dd.find('a').get('href'))
# 获取每个 a 标签 的 内容,即 每一章 的 标题名
nameList.append(dd.find('a').text + '.txt')
os.mkdir('元尊')
for i,url in enumerate(tqdm(urlList)):
req = requests.request(method="GET",url = url)
req.encoding = 'utf-8'
html = req.text
bs = BeautifulSoup(html,'lxml')
# 找到 content div 标签
content = bs.find("div",)
content = content.text.strip().split('\xa0' * 4)
f = open('元尊\\'+ nameList[i], 'w',encoding='utf-8')
for str in content:
f.write(str)
f.close()