【本帖持续更新,直到能将一本书全部爬到一个.txt文件中】
一:准备工作
爬取的网站地址:http://b.faloo.com/tag/6293.html
爬取的书:与校花同居的大盗 链接:https://b.faloo.com/f/163306.html
找到存放文本的html标签
先打开小说的第一章,我们可以采用审查元素的方式来找到这个网页的源代码。一般我们可以通过右击-审查元素 来查看网页的源代码,但这个网页跟我之前遇到的不同,右键出现的是此网页的功能。因此可以选择按F12来找到网页的源代码
但这里我选择用python中requests库的get方法来查看:
import requests
from bs4 import BeautifulSoup
url = "https://b.faloo.com/p/163306/1.html"
r = requests.get(url)
print(r.text)
结果如下:
在这里我们就可以明确地看到文本被存放在一个名为div的标签里,它的id属性为content,如此我们便锁定了要爬取的标签。
二:爬取单个章节
我们首先爬取第一章的内容:
import requests
from bs4 import BeautifulSoup
url = "https://b.faloo.com/p/163306/1.html"
try:
r = requests.get(url) #解析网页
r.raise_for_status #检查网页能否正常访问,不能则报错
html = r.text #获取网页html
soup = BeautifulSoup(html,'html.parser') #用html.parser解析器解析html
div = soup.find_all("div",id = "content")[0] #查找名为div,id属性为content的标签,由于返回的是一个列表,因此取列表里的值
print(div)
except:
print("出错了")
代码写好后,我们看下结果:
可以看到,我们已经获取了文本内容,但是里面并没有分段而且存在<br/>等这类的标签。此时如果你用type()函数检查下div的类型,可以发现它是bs4里定义的Tag类型。
事实上,我们需要的是字符串类型,当我们将其转化为字符串时,这些标签就会自己消失了。我们需要解决的,是分段问题。
我们可以看到,爬取的内容的每一段开头有几个字符的空格,我们可以将这些空格转化为换行符来达到换行的目的,因此我们选择replace方法。
代码如下:
import requests
from bs4 import BeautifulSoup
url = "https://b.faloo.com/p/163306/1.html"
try:
r = requests.get(url) #解析网页
r.raise_for_status #检查网页能否正常访问,不能则报错
html = r.text #获取网页html
soup = BeautifulSoup(html,'html.parser') #用html.parser解析器解析html
div = soup.find_all("div",id = "content")[0]
div = div.text.replace(' ','\n\n'+' ')
print(div)
except:
print("出错了")
最终运行结果如下:
到此,我们就完成了对单个章节的爬取。接下来,我将进行对整本书的爬取并生成一个txt文件来保存这些文本。
<hr color = "red"/>
2018.4.3号更新如下:
三:将整本书爬下并将文本存入一个txt文档中
在开始这部分之前,我们首先要知道如何通过代码在系统盘指定位置生成一个txt。在这里我们使用open()函数。但是,有可能我们所选择的系统盘位置已经有了一个相同文件名的文件夹或是txt文件,如何来避免我们爬取的内容将原有文件的内容给覆盖或破坏呢?
我们选择python的os模块。
编写代码如下:
import os
if not os.path.exists("D://1.txt"):
f = open('D://1.txt','w')
f.write('这是写入的内容')
f.close()
else:
print("已存在相同文件名")
os.path.exists()函数可以判断指定目录和名称的文件夹或是文件是否已经存在,如果存在,返回True,不存在返回False
上述代码第一次执行结果如下:
第二次时由于已经存在同名文件夹,所以结果如下:
好,我们现在已经可以将内容写入文本,接下来进行对整本书的爬取。
首先,我们要先分析这本书在网站上的结构。
对包含章节目录的网页进行审查元素:
我们可以看到,章节超链接指向一个<a>标签,在<a>标签中由一个属性href。在html协议中,href存放的是一个url。
我们打开第一章,看一下url。
我们发现,href前面加上一个“http:”正好就是我们想要章节的url!
那么我们就得到了获取章节链接的方法——通过获取<a>标签中的href
结构分析好后,我们就要着手尽心代码的编写了。
我们先理清思路。
1.我们需要一个函数来获取所有的章节链接,并返回一个储存所有url链接的列表
def getUrl():
return url_list
2.我们需要一个函数来循环调取url_list中的链接,并解析网页html,将所需要的文本爬取下来存到一个txt中间中
def getContent():
3.最后我们需要调取函数
好了,如上就是我们对爬取一本书的思路,三个主要的代码框架都已经列出来了,我们最后要做的就是把代码补齐:
import requests
import os
from bs4 import BeautifulSoup
main_url = "https://b.faloo.com/f/163306.html" #指定带有章节链接的url
chapter_names=[] #用于存放章节名
url_list = [] #用于存放章节链接
path = "D://与同居的大盗.txt" #指定一个根目录存放txt文件
num = 0
'''定义一个获取章节链接的函数
这个函数的作用是从main_url中提取出所有章节的链接
并且放到url_list中去,最后返回url_list
以供下一个函数使用
'''
def getUrl(url):
try:
r = requests.get(url)
r.raise_for_status
except:
print("无法获取主网页,请确认主网页")
html = r.text
soup = BeautifulSoup(html,'html.parser')
td = soup.find_all('td',class_ = "td_0")
for each in td:
url_ = 'http:' + each.a.attrs['href']
url_list.append(url_)
return url_list
'''定义一个获取章节文本的函数
这个函数的作用是将每一章的文本内容提取出来并放到txt文件中去
'''
def getContent(list,path):
if not os.path.exists(path):
with open(path,'a',encoding = 'utf-8') as f: #这里将open()放在for循环之外是为了提高效率,避免重复地打开文件。并将编码方法改为utf-8,使其能识别特殊字符。如果不加这个encoding会报编码错误,因为windows系统默认的gbk编码方式识别不了文中的特殊字符。
for url in list:
try:
r1 = requests.get(url) #解析网页 #检查网页能否正常访问,不能则报错
r1.raise_for_status
except:
print("此"+item+"章节链接无法打开,请确认网页")
html1 = r1.text #获取网页html
soup1 = BeautifulSoup(html1,'html.parser') #用html.parser解析器解析html
div = soup1.find_all("div",id = "content")[0]
content = div.text.replace(' ','\n\n'+' ')
f.write(content)
f.close
else:
print('"D://"位置已存在"与校花同居的大盗.txt",请确认')
getContent(getUrl(main_url),path)#调用函数
好了,至此,我们就完成了爬取一本书的工作。
但是,我们的代码还有很多要优化的地方,比如:
· 没有章节名
· 没有程序运行进度的提示。我们这次爬取的书比较小,如果是一本内容特别多地小说,python爬取所需要的时间会大大增加,没有进度提示的话会影响到用户的使用体验
那么,这些就是我们下一次要来完善的地方。
【未完待续】