python爬取豆瓣首页热门栏目详细流程
记录一下爬取豆瓣热门专栏的经过,通过这篇文章,你能学会requests,HTMLParser,json的基本使用,以及爬取网页内容的基本思路。
使用模块
1,获取豆瓣首页代码:首先我们需要访问豆瓣页面,获取首页的源码。这里推荐使用第三方库:requests,相比python内置的 urllib 模块,requests使用起来更简单,功能更全面
2,对获取的代码进行解析:对于解析html代码,已经有很多功能强大的框架能使用,如Scrapy,PySpider,Beautiful Soup等,这里我们只是学习下爬虫的基本使用,所以内建的 HTMLParser 足够使用了
3,对获取的数据进行处理: json
思路分析
既然我们需要的只是热门专栏模块的数据,那么我们需要一个标志来告诉我们:下面的代码就是专栏模块了,准备获取数据。同样我们需要知道当前
读取的是图片、标题还是栏目类别,以此将数据储存到相应的字段中。总的来说,我们最起码应该通过代码来实现以下几点:
1,获取网页源码
2,通过自定义方法解析html
3,通过标志位判断当前数据是否是我们需要的数据
4,通过分析代码结构决定将要储存的数据结构
5,将数据按照特定格式进行本地储存
豆瓣官网:https://www.douban.com/,分析一下我们需要爬取模块的代码:
可以看到,我们需要爬取的数据都在 ul.time-list 这个代码块里,那么我们的标志位就是:当开始标签为 ul并且具有类名 time-list时,我们就要获取数据了,当结束标签为 ul 时,停止解析,继续分析代码结构,每个 li 里面包含了对应数据里面的 详情页跳转链接,图片地址,标题以及专栏类别,那么我们的数据结构到这里也就很清楚了:一个 li 块对应一条数据,每条数据由四个字段组成:
详情页跳转链接 href --> 这里我们考虑了一下, 还是通过第二个a标签来获取,它具有统一的类名title,同时我们还能获取 标题title,
图片地址 imgUrl --> 通过每个li代码块里面唯一img标签的src属性可以轻松获取,
标题 title --> 通过 a.title获取,
专栏类别 type --> 唯一的 span 标签获取
tip:像上面我们选取数据的标志位一样,img的alt可以获取标题,a标签的文本也可以获取标题,两个a标签都能获取跳转链接不管是爬虫还是平时其他的开发,我们经常会遇到,同一个需求有多种方法实现,这时候我们就需要思考一下哪一种方法更简洁,冷静分析后的编码不一定最优秀,但自己肯定印象深刻(说远了,回归正题)。
编码实现
通过上面的准备工作,我们已经确定了需要引入的模块,解析事件触发标志位,需要获取的数据,储存的数据结构,可以正式开始编码了:
requests是第三方库,需要另外安装,其他的是内置模块,直接引入即可:
import requests
from html.parser import HTMLParser
from html.entities import name2codepoint
import json
获取豆瓣首页源码:
r = requests.get('https://www.douban.com/', timeout = 3)
是的,通过 requests获取网页只需要一行代码,timeout为获取页面超时时间,通过 r.text 就是我们需要的html源码,r.encoding可以获取网页编码格式,当然requests还有其他的方法供我们使用,
如 带参数的url: r = requests.get(url, params={.....}),获取数据等
解析豆瓣首页源码:
HTMLParser 里已经封装好了针对html的各种事件处理,如 开始标签,结束标签,标签属性,标签文本,注释,特殊字符,不了解的可以看下这个:
https://www.liaoxuefeng.com/wiki/1016959663602400/1017784593019776,很简单很清晰
class MyHTMLParser(HTMLParser):
def __init__(self):
super().__init__()
# 是否开始解析
self._allowRun = False # 创建dist备用:储存数据
self.hotList = {'data': []} # 每一个 li 块数据储存
self.listItem = {} # 当前解析标签类型的标志位
self.tagType = '' # 开始标签及 标签属性
def handle_starttag(self, tag, attrs):
if tag == 'ul' and ('class', 'time-list') in attrs:
self._allowRun = True # 若当前是开启解析状态
if self._allowRun:
if tag == 'a' and ('class', 'title') in attrs:
self.tagType = 'a'
for (key, value) in attrs:
if key == 'href':
self.listItem[key] = value
if tag == 'img':
for (key, value) in attrs:
if key == 'src':
self.listItem['imgUrl'] = value if tag == 'span':
self.tagType = 'span' # 结束标签
def handle_endtag(self, tag):
self.tagType = ''
if tag == 'ul':
self._allowRun = False if tag == 'li':
if len(self.listItem) != 0:
self.hotList['data'].append(self.listItem)
self.listItem = {} # 空标签及 标签属性
def handle_startendtag(self, tag, attrs):
if self._allowRun:
if tag == 'img':
for (key, value) in attrs:
if key == 'src':
self.listItem['imgUrl'] = value # 标签文本
def handle_data(self, data):
if self._allowRun:
if self.tagType == 'a':
self.listItem['title'] = data
self.taga = False
elif self.tagType == 'span':
self.listItem['type'] = data # 注释
def handle_comment(self, data):
pass # HTML entity 字符
def handle_entityref(self, name):
pass # Numeric 字符
def handle_charref(self, name):
pass parser = MyHTMLParser()
77 parser.feed(r.text)
代码说明:我们必须知道在解析过程中,实例方法是按照源码顺序循环执行的,也就是说在同一个实例方法里,我们可以针对不同的标签或其他条件来进行不同的操作。我们所有的解析操作都是针对 ul.time-list 代码块的,所以我们需要一个开关,当前代码是 ul.time-list时才执行我们自定义的解析操作,这个开关就是上面代码里的 _allowRun,当开始标签是 ul.time-list的是否为 True,当结束标签是 ul 的是否为False,而只有当 _allowRun 为 True的时候,我们才继续解析当前的标签是 a 还是 img 或者 span。由于我们要在 文本解析事件 handle_data 中获取 a 标签的文本作为字段 title 的值,span标签的文本作为字段 type 的值,所以我们需要一个标志位变量来供我们在执行 handle_data 的时候判断当前解析的文本是属于 a 还是 span,这个标志位变量就是上面代码中 tagType,在 handle_starttag 中赋值,在 handle_endtag 中清空。我们将每一条数据储存在 listItem 中,当结束标签为 li 时,说明我们的对一个 li 代码块解析完毕,listItem 储存了我们需要的单挑数据,将 listItem 添加到 hotList中并清空 listItem 。执行上面代码,我们已经将数据储存在实例属性 hotList里面,我们可以在终端输出 parser.hotList:
储存数据
接下来就是将数据储存到本地文件中,而写入数据也是非常简单:
with open('hotList.json', 'w') as f:
json.dump(parser.hotList, f)
在当前目录里打开 hotList.json 文件,可以看到如下数据:
数据倒是写入了,但是中文却没有如愿显示,而且对于追求美观的我们来说也无法接受,所以我们需要指定写入编码格式,以及格式化:
with open('hotList.json', 'w', encoding="utf-8") as f:
json.dump(parser.hotList, f, ensure_ascii = False, indent = 4)
我们在写入的时候指定编码格式为 utf-8: encoding="utf-8",在 json.dump写入数据时增加了两个参数:ensure_ascii = False 禁止进行 ascii转码,indent = 4:按缩进为 4个单位格式化数据,当然我们还可以将字段进行排序,只需要加上字段:sort_keys = True,按需选择即可,再打开 hotList.json 文件查看:
{
"data": [
{
"imgUrl": "https://img1.doubanio.com/dae/niffler/niffler/images/1c6e77ec-c493-11e9-84c0-0242ac110008.jpg",
"href": "https://m.douban.com/time/column/164?dt_time_source=douban-web_anonymous",
"title": "伤别离与共春风——唐宋词的情感世界",
"type": "音频专栏"
},
{
"imgUrl": "https://img1.doubanio.com/dae/niffler/niffler/images/511ccf86-b8fc-11e9-b188-0242ac110008.jpg",
"href": "https://m.douban.com/time/column/163?dt_time_source=douban-web_anonymous",
"title": "世界记忆大师教你快速提升记忆力",
"type": "视频专栏"
},
{
"imgUrl": "https://img1.doubanio.com/dae/niffler/niffler/images/74897a9e-880c-11e9-bd82-0242ac11001b.jpg",
"href": "https://m.douban.com/time/column/159?dt_time_source=douban-web_anonymous",
"title": "黑白之间:二十八堂书法练习课",
"type": "视频专栏"
},
{
"imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/6f488990-a773-11e9-b587-0242ac110011.jpg",
"href": "https://m.douban.com/time/column/161?dt_time_source=douban-web_anonymous",
"title": "马伯庸的冷门书单",
"type": "音频专栏"
},
{
"imgUrl": "https://img1.doubanio.com/dae/niffler/niffler/images/6c46cb9c-ac61-11e9-97e2-0242ac11000c.jpg",
"href": "https://m.douban.com/time/column/162?dt_time_source=douban-web_anonymous",
"title": "听!解说式音乐会——古典音乐聆听指南",
"type": "视频专栏"
},
{
"imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/ebd421cc-9968-11e9-ad2c-0242ac110006.jpg",
"href": "https://m.douban.com/time/column/158?dt_time_source=douban-web_anonymous",
"title": "从格里菲斯到诺兰——影迷都在看的电影结构大师课",
"type": "视频专栏"
},
{
"imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/fa83f054-9633-11e9-a82e-0242ac110006.jpg",
"href": "https://m.douban.com/time/column/157?dt_time_source=douban-web_anonymous",
"title": "打开电影声音的魔盒——好莱坞声音设计大师课",
"type": "视频专栏"
},
{
"imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/81788c8e-8e53-11e9-b51e-0242ac110010.jpg",
"href": "https://m.douban.com/time/column/156?dt_time_source=douban-web_anonymous",
"title": "一剧之本——好莱坞编剧教父大师课",
"type": "视频专栏"
},
{
"imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/5d7d70aa-8b25-11e9-a08f-0242ac110012.jpg",
"href": "https://m.douban.com/time/column/155?dt_time_source=douban-web_anonymous",
"title": "老叶说电影——90分钟看懂中国电影产业",
"type": "视频专栏"
},
{
"imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/e2e59078-828e-11e9-a465-0242ac110012.jpg",
"href": "https://m.douban.com/time/column/154?dt_time_source=douban-web_anonymous",
"title": "好莱坞特效大师课——从概念艺术到3D建模",
"type": "视频专栏"
}
]
}
这样就只有两个字:嘘服。
总结
这个例子只是用来熟悉爬虫基本操作和思维逻辑,真正用到项目中还是得结合其他框架,如 Beautiful Soup,就可以获取指定代码片段进行解析而不需要像我们上面那样设置开关或标志位。有兴趣的朋友可以自己动手试试。
与诸君共勉。
python爬取豆瓣首页热门栏目详细流程的更多相关文章
- Python爬取豆瓣《复仇者联盟3》评论并生成乖萌的格鲁特
代码地址如下:http://www.demodashi.com/demo/13257.html 1. 需求说明 本项目基于Python爬虫,爬取豆瓣电影上关于复仇者联盟3的所有影评,并保存至本地文件. ...
- Python爬取豆瓣指定书籍的短评
Python爬取豆瓣指定书籍的短评 #!/usr/bin/python # coding=utf-8 import re import sys import time import random im ...
- 利用Python爬取豆瓣电影
目标:使用Python爬取豆瓣电影并保存MongoDB数据库中 我们先来看一下通过浏览器的方式来筛选某些特定的电影: 我们把URL来复制出来分析分析: https://movie.douban.com ...
- Python爬取豆瓣电影top
Python爬取豆瓣电影top250 下面以四种方法去解析数据,前面三种以插件库来解析,第四种以正则表达式去解析. xpath pyquery beaufifulsoup re 爬取信息:名称 评分 ...
- python爬取豆瓣电影信息数据
题外话+ 大家好啊,最近自己在做一个属于自己的博客网站(准备辞职回家养老了,明年再战)在家里 琐事也很多, 加上自己 一回到家就懒了(主要是家里冷啊! 广东十几度,老家几度,躲在被窝瑟瑟发抖,) 由于 ...
- Python爬取豆瓣音乐存储MongoDB数据库(Python爬虫实战1)
1. 爬虫设计的技术 1)数据获取,通过http获取网站的数据,如urllib,urllib2,requests等模块: 2)数据提取,将web站点所获取的数据进行处理,获取所需要的数据,常使用的技 ...
- python 爬取豆瓣书籍信息
继爬取 猫眼电影TOP100榜单 之后,再来爬一下豆瓣的书籍信息(主要是书的信息,评分及占比,评论并未爬取).原创,转载请联系我. 需求:爬取豆瓣某类型标签下的所有书籍的详细信息及评分 语言:pyth ...
- 零基础爬虫----python爬取豆瓣电影top250的信息(转)
今天利用xpath写了一个小爬虫,比较适合一些爬虫新手来学习.话不多说,开始今天的正题,我会利用一个案例来介绍下xpath如何对网页进行解析的,以及如何对信息进行提取的. python环境:pytho ...
- python爬取豆瓣小组700+话题加回复啦啦啦python open file with a variable name
需求:爬取豆瓣小组所有话题(话题title,内容,作者,发布时间),及回复(最佳回复,普通回复,回复_回复,翻页回复,0回复) 解决:1. 先爬取小组下,所有的主题链接,通过定位nextpage翻页获 ...
随机推荐
- 《VR入门系列教程》之8---GearVR
高端移动虚拟现实设备---三星GearVR Oculus Rift也许是虚拟现实头显的典范,但是它还是存在许多问题.首先,它需要基于一个具有强大图形计算能力的计算机,而使用一般的笔记本.苹果A ...
- 分布式锁----Redis实现
分布式锁 为什么需要有分布式锁呢,在单点的时候synchronized 就能解决,但是服务拆分之后,每个服务都是单独的机器,无法解决,所以出现了分布式锁,其实也就是用各种手段,实现获取唯一锁,别人无法 ...
- 第一个C# Winform实例
前面我们准备好了相关的库,现在开始搭建环境,本人自动化行业,就用Windorm开发吧,例子仅仅做引导,希望大家能深入.VS版本VS2017 1:打开VS建立一个WInform 项目.拉入两个控件,gr ...
- 用户体验要素——产品系统设计方法
用户体验已经成为了每个互联网人的口头词,特别是互联网产品经理或产品设计师. 的确,对于任何一个互联网产品而言,体验都是非常重要的. 但是具体的用户体验到底指的是哪些方面,界面,UI,还是交互,其中到底 ...
- the license has been canceled
ideal 的 注册码并没有失效,却显示这个信息 the license has been canceled 如果用的是Windows系统,在hosts文件添加下边的ip及映射 0.0.0.0 acc ...
- 对ThreadLocal的一些理解
ThreadLocal也是在面试过程中经常被问到的,本文主要从以下三个方面来谈对ThreadLocal的一些理解: ThreadLocal用在什么地方 ThreadLocal一些细节 ThreadLo ...
- Flutter学习笔记(13)--表单组件
如需转载,请注明出处:Flutter学习笔记(13)--表单组件 表单组件是个包含表单元素的区域,表单元素允许用户输入内容,比如:文本区域,下拉表单,单选框.复选框等,常见的应用场景有:登陆.注册.输 ...
- IO流的Properties集合,序列化流与反序列化流,打印流及commons-IO
内容介绍 Properties集合 序列化流与反序列化流 打印流 commons-IO Properties类 Properties类介绍 Properties 类表示了一个持久的属性集.Proper ...
- Oracle_InstantClient 及PL/SQL Developer工具的安装
一.下载 InstantClient 地址: http://www.oracle.com/technology/software/tech/oci/instantclient/index.html i ...
- Java匹马行天下之J2EE框架开发——Spring—>用IDEA开发Spring程序(01)
一.心动不如行动 一.创建项目 *注:在IDEA中我创建的Maven项目,不了解Maven的朋友可以看我之前的博客“我们一起走进Maven——知己知彼”,了解Maven后可以看我之前的博客“Maven ...