简书搜索爬虫

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

爬虫源代码

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

# -*- 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 = 1self.host = hostself.port = portself.db_name = db_nameself.coll_name = coll_namedef get_total_pages(self):'''提取总页码数'''url = self.url.format(key=self.key, page=self.start_page)html = requests.get(url, headers=self.headers).textdata = json.loads(html)total_pages = data['total_pages']return total_pagesdef get_infos(self, page):'''提取单个页面的文章信息,格式为dict'''url = self.url.format(key=self.key, page=page)html = requests.get(url, headers=self.headers).textdata = 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 = 1self.host = hostself.port = portself.db_name = db_nameself.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).textdata = 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).textdata = 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 基本的数据分析工具来对爬取的信息进行可视化分析。

查看原文

转载于:https://www.cnblogs.com/gopythoner/p/7760548.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/415429.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

小程序滚动条隐藏

其实大家的写法估计都是如下: ::-webkit-scrollbar {width: 0;height: 0;color: transparent;}我在安卓手机上测试过,目前没有问题。

Android studio 报错:Manifest merger failed xxx

如果是提示建议添加 tools:replace"android:allowBackup" 只需修改application下属性为 android:name".YwApplication" android:allowBackup"true" android:icon"mipmap/txlogo" android:label"string/app_name" android:l…

mysql双机热备

MySQL双机热备 目录: 1、说明 2、数据手工同步 3、修改主数据库配置文件 4、修改从数据库配置文件 5、主数据库添加备份用户 6、从数据库设置为Slave 7、验证 1、说明 1)数据库版本要高于5.1 2)从数据库的版本要 > 主数据库服务器…

工作144:时间戳格式化

//日期转时间戳 function transdate(time){var date new Date();date.setFullYear(time.substring(0, 4));date.setMonth(time.substring(5, 7) - 1);date.setDate(time.substring(8, 10));date.setHours(time.substring(11, 13));date.setMinutes(time.substring(14, 16));da…

网页控制聚英继电器JY-DAM3200代码

第一次使用web控制一个实体硬件&#xff0c;需要通过网页调用串口&#xff0c;摸索了一阵子&#xff0c;终于选定用pythonphpjQueryhtml实现了。 第一部分&#xff1a;web首页界面 index.html<!DOCTYPE html><html lang"en"><head><meta charse…

monaco-editor 监听保存按钮

个人已经觉得monaco-editor比CodeMirror好了&#xff0c;所以开始研究monaco-editor。 基本用法网上很多&#xff0c;我的需求是写一段文字后&#xff0c;直接保存&#xff0c;实时在浏览器中显示效果。 但是默认的command s会直接跳出浏览器的保存网页操作&#xff0c;所以…

http://w3cschool.codecloud.net/python/python-object.html?ref=myread

Python 面向对象教程 http://w3cschool.codecloud.net/python/python-object.html?refmyread

工作145:vue里面取消console和debugger

开发过程中&#xff0c;经常需要使用console.log、console.info、alert等操作来输出内容&#xff0c;测试代码&#xff0c;而在生产环境之中&#xff0c;这些打印的东西最好是不要显示、特别是用户名、密码相关。 一个个去删除、注释显然是很麻烦的一件事&#xff0c;所以我们可…

Program type already present: android.support.design.widget.xx

主要提示错误意思是support版本问题。 解决方法&#xff1a; 统一build.gradle中所以关于support依赖的版本&#xff0c;有的25就都改为25&#xff0c;有点27就都改为27。 Sync。同步即可

推荐一个好库 热键监听 hotkeys-js

使用代码 import hotkeys from hotkeys-js hotkeys(commands, function (event, handler) {// 阻止窗体自带事件event.preventDefault()alert(you pressed commands!) })

js的加密和解密

最近在研究js的加密和解密的问题&#xff0c;上网上搜出来很多方法&#xff0c;不过不知道到底哪一个会比较管用。这里是今天找到的一些关于base64加密解密的js代码&#xff0c;已经经过试验&#xff0c;可以使用&#xff0c;不过网上很多加密解密的工具&#xff0c;这种方式加…

TCP/IP协议三次握手与四次握手流程解析

一、TCP报文格式TCP/IP协议的详细信息参看《TCP/IP协议详解》三卷本。下面是TCP报文格式图&#xff1a;图1 TCP报文格式上图中有几个字段需要重点介绍下&#xff1a;&#xff08;1&#xff09;序号&#xff1a;Seq序号&#xff0c;占32位&#xff0c;用来标识从TCP源端向目的端…

Android 使用ViewPager实现导航页面

PagerAdapter类 /*** 作者&#xff1a;created by meixi* 邮箱&#xff1a;13164716840163.com* 日期&#xff1a;2018/7/23 17*/public class GuidePageAdapter extends PagerAdapter {private List<View> views;public GuidePageAdapter(List<View> views) {thi…

js动态创建样式style

我的样式是从后台动态获取&#xff0c;前端进行渲染的&#xff0c;核心代码如下 const style .vue-preview .text {color: #4fc08d;} this.styleEl document.createElement(style) this.styleEl.type text/css this.styleEl.innerHTML style; document.getElementsByTagN…

h5有哪些新特性?

面试的时候会问到这一道题&#xff0c;根据w3school上的文档是这样的 新特性 HTML5 中的一些有趣的新特性&#xff1a; 用于绘画的 canvas 元素用于媒介回放的 video 和 audio 元素对本地离线存储的更好的支持新的特殊内容元素&#xff0c;比如 article、footer、header、nav、…

jmeter 入门操作

今天用领导交给我一个任务&#xff0c;有一个链接需要调用200次&#xff0c;但是其中的一个参数需要变化。如果要用手工&#xff0c;哦&#xff0c;&#xff2e;&#xff2f;&#xff0c;我不敢往下想。。。。。 想想jmeter强大的功能&#xff0c;就用这个来试试吧&#xff0c;…

either fix the issues identified by lint, or modify your build script as follows

Android studio 在打包时报错如下&#xff1a; Lint found fatal errors while assembling a release target. To proceed, either fix the issues identified by lint, or modify your build script as follows: ... android { lintOptions { checkReleaseBuild…

node npm包安装 save和save-dev的区别

进行npm包安装的时候&#xff0c;我们经常使用 npm install package-name --save npm install package-name --save-dev或者 yarn add package-name yarn add package-name --dev在我们本地开发&#xff0c;需要一些调试工具库的时候&#xff0c;使用--dev进行安装&#xff0…