美文网首页
5.3黑客成长日记——爬虫篇(1)

5.3黑客成长日记——爬虫篇(1)

作者: CodingFemy | 来源:发表于2020-05-03 23:18 被阅读0次

    写一个小说网站的爬虫—Test

    reference

    Python3 网络爬虫(二)
    [新笔趣阁](https://www.xsbiquge.com/
    beautiful

    爬虫三个步骤:
    发起请求:我们需要先明确如何发起 HTTP 请求,获取到数据。
    解析数据:获取到的数据乱七八糟的,我们需要提取出我们想要的数据。
    保存数据:将我们想要的数据,保存。

    首先是工具

    beautifulSoup HTML解析工具

    简介

    Beautiful Soup将复杂HTML文档转换成一个复杂的树形结构,每个节点都是Python对象,所有对象可以归纳为4种:
    -Tag #标签
    -NavigableString #内容
    -BeautifulSoup #document对象
    -Comment #注释
    后面内容请对照代码来观看

    import re
    from bs4 import BeautifulSoup
    
    #html为解析的页面获得html信息,为方便讲解,自己定义了一个html文件
    
    html = """
    <html>
    <head>
    <title>Jack_Cui</title>
    </head>
    <body>
    <p class="title" name="blog"><b>My Blog</b></p>
    <li><!--注释--></li>
    <a href="http://blog.csdn.net/c406495762/article/details/58716886" class="sister" id="link1">
    Python3网络爬虫(一):利用urllib进行简单的网页抓取</a><br/>
    <a href="http://blog.csdn.net/c406495762/article/details/59095864" class="sister" id="link2">
    Python3网络爬虫(二):利用urllib.urlopen发送数据</a><br/>
    <a href="http://blog.csdn.net/c406495762/article/details/59488464" class="sister" id="link3">
    Python3网络爬虫(三):urllib.error异常</a><br/>
    </body>
    </html>
    """
    
    #创建Beautiful Soup对象
    # soup = BeautifulSoup(html)
    soup = BeautifulSoup(html, "html.parser")
    #soup = BeautifulSoup(open('index.html'))
    
    print(soup.prettify())
    print(soup.name)
    print(soup.a.string)
    print(soup.a.contents)
    print(soup.br.contents)
    print(soup.li.contents)
    print(soup.head.contents)
    
    for i,child in  enumerate(soup.body.children):
        print("child", i, ":",child)
    
    print("\n"*10)
    print("______________")
    c = soup.find_all("a")
    c = soup.find_all(["a", 'b'])
    # c = soup.find_all([re.compile('^b')])
    print(c)
    for i in c:
        print(i.get_text())
    
    print("\n"*10)
    print("______________")
    print(soup.select('#link1'))
    print(soup.select("head > title"))
    print(soup.select("body > a")[0].get_text())
    

    Beautiful Soup 最后会把所有的节点变成树的一个属性。

    三种解析器

    三种解析器.png

    未来方便查询,同时提供了findall函数来查找:

    find_all

    1.name 参数
    name 参数可以查找所有名字为 name 的tag
    A.传[标签的]字符串
    B.传[标签的]正则表达式
    C.传[标签的]列表
    2.text 参数
    直接上文本,当然把上面标签的换成文本的,都适用,强大的解析器。
    3.keyword 参数
    传id 的
    4.class参数
    attrs={"class":"footer"}

    get_text()

    当然获得的结果会有一些标签名字在里面,方便debug,所以真正获得其内容,再来一个get_text()函数
    对应到属性里面获取内容的.string

    Css选择器

    有众多和find_all交叉的功能,但是咱也用不上
    突出说几个
    1.组合查找
    查找 p 标签中,id 等于 link1的内容,二者需要用空格分开
    查找body标签下的a标签内容,则使用 > 分隔
    ~ 表示所有其他兄弟标签;属
    + 表示第一个其他兄弟标签。

    进入正题

    代码也没上面难点,主要是三个部分
    正文解析,在原作者里没有用get_text()这个宝贝方法,可以去掉string里面所有的标签。

        target = 'https://www.xsbiquge.com/15_15338/8549128.html'
        html_context = crawer(target, i, online=False)
        # soup = BeautifulSoup(html_context, features="lxml")
        soup = BeautifulSoup(html_context, features="lxml")
        # print(soup.prettify())
        # print("\n"*10)
        # 文章标题
        title = soup.head.title.string[:-7]
        print("Mining\t\t\t", soup.title.string)
        # 文章内容
        # res = soup.select("#content")
        res = soup.find_all('div', id='content')
        if res:
            content = res[0].get_text()
            content_format = '\n    '.join(content.split('    '))
    

    next_link 处理,找到next link的方法也千奇百怪,原作者是通过目录页来找的。
    也可以像我一样在link里面找,或者是构造link(注释中)

    nl_tmp = soup.find_all('a', text="下一章")
    if nl_tmp:
        nl = nl_tmp[0].get('href')
        print(nl)
        return "https://www.xsbiquge.com" + nl
        # # constract way
        # target_head = target[:-13]
        # target_page = int(target[-12:-5])
        # # print(target_head, target_page)
        # page = str(target_page + 1)
        # return target_head + '/' + page + '.html'
    

    中间未来debug,在crawler中加了一个online的选项。主要是不想给对方的服务器太大的压力。

    def crawer(target, i, online=True):
        if online:
            req = requests.get(url = target)
            req.encoding = 'utf-8'
            # print(req.text)
            with open('spider/raw/'+str(i)+'_'+target.split('/')[-1], 'w', encoding='utf-8') as file:
                file.write(req.text)
            return req.text
        else:
            with open('spider/raw/'+str(i)+'_'+target.split('/')[-1], 'r', encoding='utf-8') as file:
                # for line in file.realines():
                html_context = file.read()
            return html_context
    

    全代码

    import requests
    from bs4 import BeautifulSoup
    
    def next_link(target):
        # read link way
        nl_tmp = soup.find_all('a', text="下一章")
        if nl_tmp:
            nl = nl_tmp[0].get('href')
            print(nl)
            return "https://www.xsbiquge.com" + nl
        # # constract way
        # target_head = target[:-13]
        # target_page = int(target[-12:-5])
        # # print(target_head, target_page)
        # page = str(target_page + 1)
        # return target_head + '/' + page + '.html'
    
    
    def crawer(target, i, online=True):
        if online:
            req = requests.get(url = target)
            req.encoding = 'utf-8'
            # print(req.text)
            with open('spider/raw/'+str(i)+'_'+target.split('/')[-1], 'w', encoding='utf-8') as file:
                file.write(req.text)
            return req.text
        else:
            with open('spider/raw/'+str(i)+'_'+target.split('/')[-1], 'r', encoding='utf-8') as file:
                # for line in file.realines():
                html_context = file.read()
            return html_context
    
    def save_by_chapter(title, content_format):
        with open("spider/cooked/"+title+'.txt', 'w', encoding='utf-8') as file:
            file.write('\n\n'+" "*10+title+'\n\n')
            file.write(content_format)
    
    
    def save_by_book(title, content_format):
        with open("spider/cooked/诡秘之主_全本.txt", 'a+', encoding='utf-8') as file:
            file.write('\n\n'+" "*10+title+'\n\n')
            file.write(content_format)
    
    
    if __name__ == '__main__':
        target = 'https://www.xsbiquge.com/15_15338/8549128.html'
        # target = "https://www.xsbiquge.com/15_15338/8549135.html"
        number_of_chapter = 20
        for i in range(number_of_chapter):
            print(target)
            html_context = crawer(target, i, online=True)
            # soup = BeautifulSoup(html_context, features="lxml")
            soup = BeautifulSoup(html_context, features="lxml")
            # print(soup.prettify())
            # print("\n"*10)
            # 文章标题
            title = soup.head.title.string[:-7]
            print("Mining\t\t\t", soup.title.string)
            # 文章内容
            # res = soup.select("#content")
            res = soup.find_all('div', id='content')
            if res:
                content = res[0].get_text()
                content_format = '\n    '.join(content.split('    '))
                save_by_chapter(title, content_format)
                save_by_book(title, content_format)
                print(title,"\t\t\tsave successfully")
            else:
                print("False Page\t\t\t", target)
            #下一章
            nl = soup.find_all('div', attrs={"class":"bottem1"})
            target = next_link(target)
    
    

    尾声

    还可以tqdm显示进度条,等等。
    对了,不推荐下载盗版小说。

    20 多分钟下载一本小说,你可能感觉太慢了。想提速,可以使用多进程,大幅提高下载速度。如果使用分布式,甚至可以1秒钟内下载完毕。
    但是,我不建议这样做。
    我们要做一个友好的爬虫,如果我们去提速,那么我们访问的服务器也会面临更大的压力。
    以我们这次下载小说的代码为例,每秒钟下载 1 个章节,服务器承受的压力大约 1qps,意思就是,一秒钟请求一次。
    如果我们 1 秒同时下载 1416 个章节,那么服务器将承受大约 1416 qps 的压力,这还是仅仅你发出的并发请求数,再算上其他的用户的请求,并发量可能更多。
    如果服务器资源不足,这个并发量足以一瞬间将服务器“打死”,特别是一些小网站,都很脆弱。
    过大并发量的爬虫程序,相当于发起了一次 CC 攻击,并不是所有网站都能承受百万级别并发量的。
    所以,写爬虫,一定要谨慎,勿给服务器增加过多的压力,满足我们的获取数据的需求,这就够了。
    你好,我也好,大家好才是真的好。

    使用一:帮师父爬取小说
    至尊龙帝陆鸣
    和上面的主要区别是gbk
    全代码

    #!/usr/bin/python
    
    import requests
    from bs4 import BeautifulSoup
    
    def next_link(soup):
        # read link way
        nl_tmp = soup.find_all('a', text="下一章")
        if nl_tmp:
            nl = nl_tmp[0].get('href')
            print(nl)
            return "https://www.rzlib.net" + nl
        # # constract way
        # target_head = target[:-13]
        # target_page = int(target[-12:-5])
        # # print(target_head, target_page)
        # page = str(target_page + 1)
        # return target_head + '/' + page + '.html'
    
    
    def crawer(target, i, online=True):
        if online:
            req = requests.get(url = target, headers={'User-Agent': 'Chrome'})
            req.encoding = 'GBK'
            # print(req.text)
            with open('spider/raw/'+str(i)+'_'+target.split('/')[-1], 'w') as file:
                file.write(req.text)
            return req.text
        else:
            with open('spider/raw/'+str(i)+'_'+target.split('/')[-1], 'r') as file:
                # for line in file.realines():
                html_context = file.read()
            return html_context
    
    
    def save_by_chapter(title, content_format):
        with open("spider/cooked/"+title+'.txt', 'w', encoding='utf-8') as file:
            file.write('\n\n'+" "*10+title+'\n\n')
            file.write(content_format)
    
    
    def save_by_book(title, content_format):
        with open("spider/cooked/至尊龙帝陆鸣1360plus.txt", 'a+', encoding='utf-8') as file:
            file.write('\n\n'+" "*10+title+'\n\n')
            file.write(content_format)
    
    rpstr = []
    
    if __name__ == '__main__':
        target = 'https://www.rzlib.net/b/73/73820/32494178.html'
        number_of_chapter = 3200
        for i in range(number_of_chapter):
            print(target)
            html_context = crawer(target, i, online=True)
            # soup = BeautifulSoup(html_context, features="lxml")
            soup = BeautifulSoup(html_context, "html5lib")
            # print(soup.prettify())
            # print("\n"*10)
            # 文章标题
            title = soup.head.title.string[:-7]
            print("Mining\t\t\t", soup.title.string)
            # 文章内容
            # res = soup.select("#content")
            res = soup.find_all('div', id='chapter_content')
            if res:
                content_format = content = res[0].get_text()
                for a, b in rpstr:
                    content_format = content_format.replace(a,b)
                # save_by_chapter(title, content_format)
                save_by_book(title, content_format)
                print(title,"\t\t\tsave successfully")
            else:
                print("False Page\t\t\t", target)
            #下一章
            nl = soup.find_all('div', attrs={"class":"bottem1"})
            target = next_link(soup)
    

    中途遇到了error,max retry啥的,没解决。重跑了两次,第三次就好了。

    Connection aborted.', RemoteDisconnected('Remote end closed connection without response
    添加
    headers = {'User-Agent': 'User-Agent:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36'}

    相关文章

      网友评论

          本文标题:5.3黑客成长日记——爬虫篇(1)

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