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

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

作者: 羽落青衫薄 | 来源:发表于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