爬虫实践---抓取小说网站

 

电子书网站:

http://www.qu.la/paihangbang/

 

对网页进行分析可知,

 
玄幻奇幻排行
武侠仙侠排行
历史军事排行
完本小说排行


观察发现,历史军事和完本小说的时一致的,其余类别是一样的,所以进行分开处理。

每一个分类都是包裹在: 

之中 这种调理清晰的网站,大大方便了我们爬虫的编写

一个类别里,出现了排行榜上所有的小说:


玄幻奇幻排行



  • 08-011.太古神王



  • 标题:title = div.a['title'] 链接:link = 'http://www.qu.la/' + div.a['href']

     

    比如小说太古神王链接==http://www.qu.la/book/4140/

    观察可知==网站链接+书本链接

     

    由于在总//月排行中难免出现重复的电子书,所以进行了列表去重操作:


    列表去重的小技巧:

    尤其是在面对爬大量网页的时候,会浪费大量的资源,那么我们如何从抓取的url列表里去重呢? 刚学Python的小伙伴可能会去实现一个循环算法,来去重, 但是Python的强大之处就在于他可以通过及其优美的方式来解决很多问题,这里其实只要一行代码就能解决: url_list = list(set(url_list)) 这里我们调用了一个list的构造函数set:这样就能保证列表里没有重复的元素了。

     

     

    然后我们对于电子书《择天记》进行操作:

     

    观察网页信息可知,



     

    link='http://www.qu.la/' + url.a['href']

     

    打开各章节的内容,查看可知:

     


    我们能发现所有的正文内容,都保存在:

    所有的章节名就更简单了:

    第一章 我改主意了

    那我们通过bs4库的各种标签的查找方法,就能很简单的找到啦 好了,让我们看看具体代码的实现:

    打开任意章节:

        ;
      
          世界是相对的。
      
          中土大陆隔着海洋与大西洲遥遥相对。东方地势较高,那里的天空似乎也高了起来,云雾从海上陆地上升腾而起,不停向着那处飘去,最终汇聚在一起,终年不散。
      
    ......


    开始处,id="content"

    结尾处,chaptererror();

    这里有个小技巧: 我们从网上趴下来的文件很多时候都是带着
    之类的格式化标签, 我们可以通过一个简单的方法把他过滤掉: 

    html = get_html(url).replace('
    ', '\n')


    #!/usr/bin/env python
    # coding=utf-8
    
    import requests
    import bs4
    
    def get_html(url): #网页内容抓取
        try:
            r = requests.get(url,timeout=30)
            r.raise_for_status
            r.encoding = r.apparent_encoding
            # r.encoding = 'utf-8'
            return r.text
        except:
            print("Open Error!!!")
    
    
    def get_content(url):
        """
        爬取每一类型小说排行榜,
        按顺序写入文件,
        文件内容为 小说名字+小说链接
        将内容保存到列表
        并且返回一个装满url链接的列表
        """
    
        url_list = []
        html = get_html(url)
        # 煮汤
        soup = bs4.BeautifulSoup(html,'lxml')
    
        # 看到历史类和完本类的小说与其他小说不在一个div,分开读取
        category_list = soup.find_all('div', attrs={'class:','index_toplist mright mbottom'})
        # 匹配历史和完本类别的数目
        histoty_finished_list = soup.find_all('div', attrs={'class:','index_toplist mbottom'})
    
        for cate in category_list:
            name = cate.find('div',attrs={'class:','toptab'}).span.string
            with open('novel_list.csv', 'a+') as f:
                f.write("\n小说种类:{} \n".format(name))
            # 通过id来对总排行榜进行定位,
            general_list = cate.find(style='display: block;')
            # 找到全部小说名字,发现她们全部都包含在li标签中
            book_list = general_list.find_all('li')
            # 循环遍历每一个小说的名字以及链接
            for book in book_list:
                link = 'http://www.qu.la/' + book.a['href']
                title = book.a['title']
                # 将所有文章的url地址保存在一个列表变量里
                url_list.append(link)
                # 这里使用a模式,防止清空文件
                with open('novel_list.csv','a') as f:
                    f.write("小说名: {:<} \t 小说地址: {:<} \n".format(title, link))
        
        for cate in histoty_finished_list:
            name = cate.find('div', class_='toptab').span.string
            with open('novel_list.csv', 'a') as f:
                f.write("\n小说种类:{} \n".format(name))
            
            general_list = cate.find(style='display: block;') #找到总排行榜
            book_list = general_list.find_all('li')
            for book in book_list:
                link = 'http://www.qu.la/' + book.a['href']
                title = book.a['title']
                url_list.append(link)
                with open('novel_list.csv', 'a') as f:
                    f.write("小说名:{:<} \t 小说地址:{:<} \n".format(title, link))
        return url_list 
    
    def get_txt_url(url):
        """
        获取每个章节的url地址:
        并创建小说文件
        """
        url_list = []
        html = get_html(url)
        soup =bs4.BeautifulSoup(html,'lxml')
    
        lista = soup.find_all('dd')
        # dd是包含小说每一章节链接
        txt_name = soup.find('h1').text
        # h1 是小说标题
        with open ('小说/{}.txt'.format(txt_name),"a+") as f:
            print("小说:%s文件创建成功!" %txt_name)
            f.write('小说标题:{}\n'.format(txt_name))
        for url in lista:
            url_list.append('http://www.qu.la/' + url.a['href'])
    
        return url_list, txt_name
    
    def get_one_txt(url, txt_name):
        """获取小说每个章节文本并写入到本地"""
    
        html = get_html(url).replace('
    ', '\n') soup = bs4.BeautifulSoup(html,'lxml') try: txt = soup.find('div', id='content').text.replace('chaptererror();','') title = soup.find('title').text # 观察正文可知,里面的原文可以扣取出来 with open ('小说/{}.txt'.format(txt_name),"a") as f: f.write(title+'\n\n') f.write(txt) print("当前小说:{} 当前章节:{} 已经下载完毕".format(txt_name,title)) except: print("Something wrong") def get_all_txt(url_list): """下载排行榜里所有的小说 并保存为txt格式 """ for url in url_list: # 获取当前小说的所有章节目录 # 并且声称小说头文件 page_list, txt_name = get_txt_url(url) """ for page_url in page_list: # 遍历每一篇小说,并下载到目录 get_one_txt(page_url, txt_name) print('当前进度 {}% '.format(url_list.index(url) / len(url_list) * 100)) """ def main(): # 排行榜地址 base_url = 'http://www.qu.la/paihangbang/' # 获取排行榜中所有小说链接 url_list = get_content(base_url) #除去重复小说 url_list = list(set(url_list)) get_all_txt(url_list) if __name__=='__main__': main()


    缺点:
    本次爬虫写的这么顺利,更多的是因为爬的网站是没有反爬虫技术,以及文章分类清晰,结构优美。 但是,按照我们的这篇文的思路去爬取小说,我大概计算了一下: 一篇文章需要:0.5s 一本小说(1000张左右):8.5分钟 全部排行榜(60本): 8.5小时!
    这种单线程的爬虫,速度如何能提高呢?



    原作者链接:

    每天的学习记录都会 同步更新到: 微信公众号: findyourownway
    知乎专栏:https://zhuanlan.zhihu.com/Ehco-python
    blog : www.ehcoblog.ml
    Github: https://github.com/Ehco1996/Python-crawler

     

     

     

     

    你可能感兴趣的:(爬虫,python,Python爬虫)