• 简书搜索爬虫


    这期的爬虫是爬取“简书”的搜索结果页,篇幅将会分为两部分来写,第一部分是爬虫部分,主要涉及搜索文章的提取和数据保存,第二部分涉及基本的数据分析和可视化,本篇文章属于爬虫篇。

    爬虫源代码

    首先看一下整个爬虫的源代码,每个函数的用处已经写在函数说明中,后面也会进行代码解读。

    # -*- coding: utf-8 -*-
    import requests
    import json
    from urllib.parse import quote
    from pymongo import MongoClient
    
    """
    简书搜索爬虫
    输入搜索关键词,将搜索到的所有文章爬取下来
    数据保存到 mongodb 中
    """
    
    
    class JianshuSearch(object):
        def __init__(self, db_name, coll_name, key, host='127.0.0.1', port=27017):
            self.headers = {
                "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
                              "Chrome/57.0.2987.110 Safari/537.36"
            }
            self.url = 'http://www.jianshu.com/search/do?q={key}&type=note&page={page}&order_by=default'
            self.key = quote(key)
            self.start_page = 1
            self.host = host
            self.port = port
            self.db_name = db_name
            self.coll_name = coll_name
    
        def get_total_pages(self):
            '''提取总页码数'''
            url = self.url.format(key=self.key, page=self.start_page)
            html = requests.get(url, headers=self.headers).text
            data = json.loads(html)
            total_pages = data['total_pages']
            return total_pages
    
        def get_infos(self, page):
            '''提取单个页面的文章信息,格式为dict'''
            url = self.url.format(key=self.key, page=page)
            html = requests.get(url, headers=self.headers).text
            data = json.loads(html)
            entries = data['entries']
            for each in entries:
                self.save_infos(each)
    
        def save_infos(self, entry):
            '''保存一个文章的信息'''
            coon = MongoClient(host=self.host, port=self.port)
            coll = coon[self.db_name][self.coll_name]
            coll.insert(entry)
    
        def main(self):
            '''主函数,循环迭代进行翻页,提取所有页码的信息并保存到数据库'''
            total_pages = int(self.get_total_pages())
            for i in range(1, total_pages + 1):
                self.get_infos(i)
                print('总计{}页,已经爬完{}页'.format(total_pages, i))
    
    
    if __name__ == '__main__':
        DB_NAME = 'jianshu'
        COLL_NAME = 'search_result'
        key = 'python'
        spider = JianshuSearch(key=key, db_name=DB_NAME, coll_name=COLL_NAME)
        spider.main()
    

    爬虫思路

    基本思路

    爬虫的基本思路依然分为3个主要步骤:

    1. 找到入口,即起始页面的 URL
    2. 找到翻页的规律
    3. 选择有效的方式进行翻页,提取所有信息

    查看页面主要信息

    首先在简书的搜索框中输入任意一个关键词,例如“Python”,然后点击搜索按钮,查看结果页面。

    结果页面如下图所示:

    搜索结果

    可以看到,搜索的结果包含了很多种类的信息,有“相关用户”、“相关专题”和“相关文章”,并且文章的排序还可以选择条件。

    由于这里只需要提取搜索文章的信息,因此可以先看一下搜索到的文章列表中包含哪些可以收集的信息,以便后续查找和保存数据。

    找到入口——第一个 URL

    当然,一般来说,很多时候,我们看到的信息其实并不是眼前的页面给我们的信息,而是当前页面从其他地方“搬”过来的信息。如果使用或者知道ajax 的用法,这句话就很好理解,当然,不理解也无妨,并不影响后续操作。

    打开浏览器的开发者界面,可以使用快捷键 F12。刷新一下搜索的页面,然后进入 Network,看看浏览器中加载了什么页面。

    一般可以先从 Doc中查看,也就是网页源代码,但是这次的爬虫可以看到源代码中并没有搜索的结果页,于是可以继续查看 js,发现好像也没有新加载页面,继续查看 XHR,终于找到了刷新页面加载出来的页面请求,具体看截图:

    请求

    看截图中的编号,编号1就是页面加载的地方,编号2可以看到请求的 URL,编号3就是 URL 的组成,可以从中查看链接的构成规律,这里的规律就是链接中有2个关键参数,第一个参数就是搜索的关键词,这里用 q=Python表示,然后第二个参数就是当前页码,这里是 page=2,从这里就可以直接联想到,如果知道总页码数,那就可以使用循环来得到所有页码的 URL。编号4是请求的方式,这里是 GET。

    选择翻页方式

    经过这个页面,就可以把整个爬虫的思路理清楚了:

    • 首先,想办法找到总页码数
    • 然后提取单页的信息,并且保存到数据库中
    • 使用循环方式,提取所有页的信息

    源码解读

    首先需要导入相关库:

    import requests
    import json
    from urllib.parse import quote
    from pymongo import MongoClient
    
    

    这4个库的作用分别是:

    1. 网页请求
    2. 将字符串格式转换成 json 格式
    3. 将一般字符串转换成 URL 可以读取的格式
    4. python 连接 mongodb 的依赖

    爬虫类的创建

    由于这个爬虫是创建了一个爬虫类,所以需要按照 Python类的规范来,首先初始化类,通过函数来实现:

    def __init__(self, db_name, coll_name, key, host='127.0.0.1', port=27017):
        self.headers = {
            "user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
                          "Chrome/57.0.2987.110 Safari/537.36"
        }
        self.url = 'http://www.jianshu.com/search/do?q={key}&type=note&page={page}&order_by=default'
        self.key = quote(key)
        self.start_page = 1
        self.host = host
        self.port = port
        self.db_name = db_name
        self.coll_name = coll_name
    

    这里给类传递了5个参数,其中3个是没有给予默认值的参数,2个是给了默认值的参数,每个参数的含义:

    • key:搜索的关键词
    • db_name:数据库名称
    • coll_name:数据表名称
    • host,port:链接数据库的地址和端口

    提取总页码数

    可以通过爬取任意一个页码,然后打印一下提取的信息,看看信息的构成。

    通过打印信息可以发现,每个页面的信息都是一个字典格式,因此可以通过json模块来转换成 Python 的 dict 格式,然后可以发现每页都有一个参数是“total_pages”,这个参数就提供了当前搜索的结果总页码数,因此可以通过函数来提取这个参数的值:

    def get_total_pages(self):
        '''提取总页码数'''
        url = self.url.format(key=self.key, page=self.start_page)
        html = requests.get(url, headers=self.headers).text
        data = json.loads(html)
        total_pages = data['total_pages']
        return total_pages
    

    提取当个页面的信息,并保存到数据库

    由于每个页面的信息都是一个 json 格式,所以信息的提取方式很简单,直接从字典中提取就行了:

    def get_infos(self, page):
        '''提取单个页面的文章信息,格式为dict'''
        url = self.url.format(key=self.key, page=page)
        html = requests.get(url, headers=self.headers).text
        data = json.loads(html)
        entries = data['entries']
        for each in entries:
            self.save_infos(each)
    

    函数的思路很简单,首先通过 requests 请求网页,然后得到一个json类型的信息,但是由于这个信息的格式是 str, 所以需要使用 json.loads 方法转换成 dict 格式。然后使用字典的键值对关系提取到总页码数就可以了。

    这个函数的最后面用到了一个保存信息的函数,也就是后面要说的将数据保存到数据库中。

    def save_infos(self, entry):
        '''保存一个文章的信息'''
        coon = MongoClient(host=self.host, port=self.port)
        coll = coon[self.db_name][self.coll_name]
        coll.insert(entry)
    
    

    保存到数据库的函数需要传入一个参数,是一个 dict 类型,这个参数正好可以理解为提取的单个文章的信息。

    首先,按照 mongodb 的连接方式建立一个连接,这个连接就使用到了创建类的时候传入的数据库的参数,然后使用 insert()方法就可以插入数据了。

    循环提取所有页面的信息

    讲过上述的的函数,已经可以提取总页码数,也可以提取并保存单个页码的文章信息了,剩下的就是使用循环来提取所有页码的信息了,于是,可以把这个过程写到一个主函数中:

    def main(self):
        '''主函数,循环迭代进行翻页,提取所有页码的信息并保存到数据库'''
        total_pages = int(self.get_total_pages())
        for i in range(1, total_pages + 1):
            self.get_infos(i)
            print('总计{}页,已经爬完{}页'.format(total_pages, i))
    
    

    为了方便查看爬虫的进度,在每爬取一页信息,可以打印当前的进度。

    运行爬虫

    最后一段代码就是运行爬虫,首先给定一些需要传递到爬虫类中的参数,然后启动爬虫的主程序即可看到爬虫结果。

    查看数据库中信息

    “Python”这个字段在简书中有100页的数据(如果没有猜错,这个100页应该是简书默认提供的最大页码数),所以爬虫运行的时间并不长,爬完之后可以使用可视化工具看看数据库中的信息。

    数据库中信息如图:

    数据库

    后记:从数据库中可以查看到一些有效信息,包括文字的标题、链接、发布时间、作者的信息、评论数、阅览量、喜欢数等。虽然这些数据并没有什么研究价值,但是本着练手的想法,后续会使用 Python 基本的数据分析工具来对爬取的信息进行可视化分析。

    查看原文

  • 相关阅读:
    20192415 202120222 《网络与系统攻防技术》实验七实验报告
    C#字符串压缩
    linux服务器登录mysql报错bash: mysql: command not found
    java读取含有合并单元格的Excel
    修改序列号:当序列号小于主键ID的时候如何处理?
    1130 is not allowed to connect to this MySql server
    报错: java.lang.IllegalStateException: Cannot get a STRING value from a NUMERIC cell
    报错:There is no getter for property named 'distinct' in
    报错:违反检查约束条件 (GYPTS.SYS_C0016857)
    vue代码如何实现平方米m2
  • 原文地址:https://www.cnblogs.com/gopythoner/p/7760548.html
Copyright © 2020-2023  润新知