美文网首页
爬虫实战(一)——爬取网络小说

爬虫实战(一)——爬取网络小说

作者: 羽落青衫薄 | 来源:发表于2020-03-28 17:04 被阅读0次

——————————本文仅用于技术交流,支持正版——————————

爬虫学到了一丢丢,就开始了实战之旅,第一次实战,来点简单的,我们来爬一本小说。

对网页结构进行分析

网上随便找了本小说,按下我们最热爱的F12,打开开发者工具,按下图所示操作。

点击开发者工具左上角的小箭头,鼠标指向章节链接的位置,不要点击!开发者工具就会自动显示这一部分所对应的源代码,我们能发现每个章节的链接都是在a标签。我们就可以用正则表达式将每个章节的链接都找出来。

而每一章节的内容是这样的:

我们再查看网页的源代码,如下图:

含无用的script

发现不仅有我们所需要的小说内容,还有一些无用的script。之后还需要处理。

获取网页的请求头

Headers

我们以这个章节目录为例,打开开发者工具,点击Network,会出现如图所示界面,若没有,刷新一下即可。然后点击3392/,而我们所需要的在Request Headers里。将该目录下的信息提取,存放到字典中,其中最重要的是User-Agent,仅将其存放到我们的headers字典中也行,其代表了我们的身份信息,浏览器的User-Agent一般都有Mozilla/5.0

headers = {
            "user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"
          }

所需要的库文件

  • requests:用于get请求

  • bs4:网页解析

  • re:正则表达式

  • os:系统相关操作

  • time:获取时间

  • random:得到一个随机数

import requests, re, os, time, random
from bs4 import BeautifulSoup

获得章节目录的链接

headers = {
 "user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"
 }
​
try:
 r = requests.get(url, headers=headers)
 #get请求的状态,get失败会报错
 r.raise_for_status()
 #修改get到的编码
 r.encoding = r.apparent_encoding
except:
 print("爬取失败")
​
#用正则表达式获取每一章节的url
urls = re.findall('<li ><a href="(.*?)">.*?</a></li>', r.text)</pre>

关于requests的操作可以参考我之前写的博客:
小白学爬虫——Requests.get()
小白学爬虫——爬取网页的基本框架

这里讲一下re.findall

findall

在字符串中找到正则表达式所匹配的所有子串,并返回一个列表,如果没有找到匹配的,则返回空列表。 .*?表示中间为任意字符串,而加了(.*?)表示仅保留括号中的内容。

这里我们就把含链接的源代码复制过来,链接部分用(.*?)代替,而其余无用项且不相同的部分用.*?代替,即可保存括号中的内容,即a标签中的链接。 得到urls。

在这里插入图片描述

获取单章的内容

由于得到的urls只有后半部分,所以我们需要手动添加前半部分的url。

    url_source = "https://www.boquge.com"

    url = url_source + urls[0]
    
    try:
        r = requests.get(url, headers = headers)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
    except:
        print("爬取失败")

接下来对返回的response对象进行处理。

title = re.findall('<div id="h1" class="text-center"><h1>(.*?)</h1><br/>', r.text)
​
soup = BeautifulSoup(r.text, "html.parser")
texts = soup.select('#chapter #txtContent')[0]
​
for ss in texts.select("script"):
 #删除无用项
 ss.decompose()

#按照指定格式替换章节内容,运用正则表达式
text=re.sub( '\s+', '\r\n\t', texts.text).strip('\r\n')</pre>

得到标题的方法已经讲过了,现在要讲BeautifulSoup了。

BeautifulSoup,又称美丽汤,提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。 而"html.parser"是用来指定BeautifulSoup的解析器的。除此之外还有不少解析器,不再一一举例。

.select()方法是对标签进行查找和筛选,返回一个列表,筛选方法是:

  • 标签名不加任何修饰

  • 类名前加点

  • id名前加 #

  • 上下级之间用空格隔开

比如此处

第一级id=“chapter”,第二级id=“txtContent”

texts = soup.select('#chapter #txtContent')[0]

上文也提到了要把无用的script去掉,再用re.sub将其替换为string格式,即可得到我们的文本。

将获取的文本写入txt文件

#文件路径
dir_path = "/Users/ouusen/Documents/"
if not os.path.exists(dir_path):
 #若无该文件夹,则建立一个文件夹
 os.mkdirs(dir_path)
#打开并写入文本
with open(dir_path + "/" + title + ".txt",'a') as f:
 f.write(title[0] + '\n')
 f.write(text[:-1])
 f.close()

open中,'a'表示打开的时候将指针指向最后,即追加文本。

获取整本小说

# -*- coding: utf-8 -*-
import requests, re, os, time, random
from bs4 import BeautifulSoup

start_time = time.time()

url = "https://www.boquge.com/book/3392/"
headers = {
            "user-agent":"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.149 Safari/537.36"
          }

try:
    r = requests.get(url, headers = headers)
    r.raise_for_status()#get请求的状态,get失败会报错
    r.encoding = r.apparent_encoding
except:
    print("爬取失败")

dir_path = "/Users/ouusen/Documents/"
if not os.path.exists(dir_path):
    os.mkdirs(dir_path)

urls = re.findall('<li ><a href="(.*?)">.*?</a></li>', r.text)
url_source = "https://www.boquge.com"

i = 0;
for url in urls:
    url = url_source + url
    
    try:
        r = requests.get(url, headers = headers)
        r.raise_for_status()
        r.encoding = r.apparent_encoding
    except:
        print("爬取失败")
        
    soup = BeautifulSoup(r.text, "html.parser")
    title = re.findall('<div id="h1" class="text-center"><h1>(.*?)</h1><br/>', r.text)
    texts = soup.select('#chapter #txtContent')[0]
    
    for ss in texts.select("script"): 
        #删除无用项
        ss.decompose()
    #按照指定格式替换章节内容,运用正则表达式
    text=re.sub( '\s+', '\r\n\t', texts.text).strip('\r\n')
    with open(dir_path + "/" + "最强狂兵.txt",'a') as f:
        f.write(title[0] + '\n')
        f.write(text[:-1])
        f.close()
       
    i += 1
    # 每过一段时间就停顿一段时间
    if random.random()>0.75:
        print("已下载{}%".format( i*100 / len(urls) ) )
        time.sleep(2 * random.random())

end_time = time.time()
print("爬取成功,共计用时:{}".format(end_time - start_time))

写在最后

爬取小说的每个章节有两种方法,可以用上述方式,从目录中保存每个章节的链接,也可以从第一个章节开始,提取下一章的链接,第一种的空间复杂度肯定更大,不过时间复杂度就不得而知了。感兴趣的朋友们可以试试修改一下代码,比较一下。不过由于CPU的计算有波动,比较一次是不够的,需要比较多次取平均值才行。
感觉还不错的朋友们点个赞吧。

相关文章

网友评论

      本文标题:爬虫实战(一)——爬取网络小说

      本文链接:https://www.haomeiwen.com/subject/xbojuhtx.html