整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:

python爬取豆瓣首页热门栏目详细流程

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是第三方库,需要另外安装,其他的是内置模块,直接引入即可:

1 import requests
2 from html.parser import HTMLParser
3 from html.entities import name2codepoint
4 import json

获取豆瓣首页源码:

1 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,很简单很清晰

 1 class MyHTMLParser(HTMLParser):
 2 def __init__(self):
 3 super().__init__()
 4 # 是否开始解析
 5 self._allowRun=False
 6 
 7 # 创建dist备用:储存数据
 8 self.hotList={'data': []}
 9 
10 # 每一个 li 块数据储存
11 self.listItem={}
12 
13 # 当前解析标签类型的标志位
14 self.tagType=''
15 
16 # 开始标签及 标签属性
17 def handle_starttag(self, tag, attrs):
18 if tag=='ul' and ('class', 'time-list') in attrs:
19 self._allowRun=True
20 
21 # 若当前是开启解析状态
22 if self._allowRun:
23 if tag=='a' and ('class', 'title') in attrs:
24 self.tagType='a'
25 for (key, value) in attrs:
26 if key=='href':
27 self.listItem[key]=value
28 if tag=='img':
29 for (key, value) in attrs:
30 if key=='src':
31 self.listItem['imgUrl']=value
32 
33 if tag=='span':
34 self.tagType='span'
35 
36 # 结束标签
37 def handle_endtag(self, tag):
38 self.tagType=''
39 if tag=='ul':
40 self._allowRun=False
41 
42 if tag=='li':
43 if len(self.listItem) !=0:
44 self.hotList['data'].append(self.listItem)
45 self.listItem={}
46 
47 # 空标签及 标签属性
48 def handle_startendtag(self, tag, attrs):
49 if self._allowRun:
50 if tag=='img':
51 for (key, value) in attrs:
52 if key=='src':
53 self.listItem['imgUrl']=value
54 
55 # 标签文本
56 def handle_data(self, data):
57 if self._allowRun:
58 if self.tagType=='a':
59 self.listItem['title']=data
60 self.taga=False
61 elif self.tagType=='span':
62 self.listItem['type']=data
63 
64 # 注释
65 def handle_comment(self, data):
66 pass
67 
68 # HTML entity 字符
69 def handle_entityref(self, name):
70 pass
71 
72 # Numeric 字符
73 def handle_charref(self, name):
74 pass
75 
76 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:

储存数据

接下来就是将数据储存到本地文件中,而写入数据也是非常简单:

1 with open('hotList.json', 'w') as f:
2 json.dump(parser.hotList, f)

在当前目录里打开 hotList.json 文件,可以看到如下数据:

数据倒是写入了,但是中文却没有如愿显示,而且对于追求美观的我们来说也无法接受,所以我们需要指定写入编码格式,以及格式化:

1 with open('hotList.json', 'w', encoding="utf-8") as f:
2 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 文件查看:

 1 {
 2 "data": [
 3 {
 4 "imgUrl": "https://img1.doubanio.com/dae/niffler/niffler/images/1c6e77ec-c493-11e9-84c0-0242ac110008.jpg",
 5 "href": "https://m.douban.com/time/column/164?dt_time_source=douban-web_anonymous",
 6 "title": "伤别离与共春风——唐宋词的情感世界",
 7 "type": "音频专栏"
 8 },
 9 {
10 "imgUrl": "https://img1.doubanio.com/dae/niffler/niffler/images/511ccf86-b8fc-11e9-b188-0242ac110008.jpg",
11 "href": "https://m.douban.com/time/column/163?dt_time_source=douban-web_anonymous",
12 "title": "世界记忆大师教你快速提升记忆力",
13 "type": "视频专栏"
14 },
15 {
16 "imgUrl": "https://img1.doubanio.com/dae/niffler/niffler/images/74897a9e-880c-11e9-bd82-0242ac11001b.jpg",
17 "href": "https://m.douban.com/time/column/159?dt_time_source=douban-web_anonymous",
18 "title": "黑白之间:二十八堂书法练习课",
19 "type": "视频专栏"
20 },
21 {
22 "imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/6f488990-a773-11e9-b587-0242ac110011.jpg",
23 "href": "https://m.douban.com/time/column/161?dt_time_source=douban-web_anonymous",
24 "title": "马伯庸的冷门书单",
25 "type": "音频专栏"
26 },
27 {
28 "imgUrl": "https://img1.doubanio.com/dae/niffler/niffler/images/6c46cb9c-ac61-11e9-97e2-0242ac11000c.jpg",
29 "href": "https://m.douban.com/time/column/162?dt_time_source=douban-web_anonymous",
30 "title": "听!解说式音乐会——古典音乐聆听指南",
31 "type": "视频专栏"
32 },
33 {
34 "imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/ebd421cc-9968-11e9-ad2c-0242ac110006.jpg",
35 "href": "https://m.douban.com/time/column/158?dt_time_source=douban-web_anonymous",
36 "title": "从格里菲斯到诺兰——影迷都在看的电影结构大师课",
37 "type": "视频专栏"
38 },
39 {
40 "imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/fa83f054-9633-11e9-a82e-0242ac110006.jpg",
41 "href": "https://m.douban.com/time/column/157?dt_time_source=douban-web_anonymous",
42 "title": "打开电影声音的魔盒——好莱坞声音设计大师课",
43 "type": "视频专栏"
44 },
45 {
46 "imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/81788c8e-8e53-11e9-b51e-0242ac110010.jpg",
47 "href": "https://m.douban.com/time/column/156?dt_time_source=douban-web_anonymous",
48 "title": "一剧之本——好莱坞编剧教父大师课",
49 "type": "视频专栏"
50 },
51 {
52 "imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/5d7d70aa-8b25-11e9-a08f-0242ac110012.jpg",
53 "href": "https://m.douban.com/time/column/155?dt_time_source=douban-web_anonymous",
54 "title": "老叶说电影——90分钟看懂中国电影产业",
55 "type": "视频专栏"
56 },
57 {
58 "imgUrl": "https://img3.doubanio.com/dae/niffler/niffler/images/e2e59078-828e-11e9-a465-0242ac110012.jpg",
59 "href": "https://m.douban.com/time/column/154?dt_time_source=douban-web_anonymous",
60 "title": "好莱坞特效大师课——从概念艺术到3D建模",
61 "type": "视频专栏"
62 }
63 ]
64 }

这样就只有两个字:嘘服。

总结

这个例子只是用来熟悉爬虫基本操作和思维逻辑,真正用到项目中还是得结合其他框架,如 Beautiful Soup,就可以获取指定代码片段进行解析而不需要像我们上面那样设置开关或标志位。有兴趣的朋友可以自己动手试试。

文的文字及图片来源于网络,仅供学习、交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理

爬虫–scrapy

题目:根据豆瓣读书top250,根据出版社对书籍数量分类,绘制饼图

搭建环境

import scrapy
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

加载scrapy框架


#terminal 终端实现
cd .. # 跳转到上一层目录
scrapy startproject booktop # 和项目同名的scrapy框架项目

setting配置

ROBOTSTXT_OBEY=False # 君子协议 false 不遵守
USER_AGENT='Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36
(KHTML, like Gecko) Chrome/85.0.4183.121 Safari/537.36'
DOWNLOAD_DELAY=0.5 # 下载延迟## 如何改变文本的样式

spider编写


#spiders文件夹下创建python文件 bookspider.py
import scrapy
from booktop.items import BookItem
class BookSpider(scrapy.Spider):
		name="bookspider"
		allowed_domains=['book.douban.com']
		start_urls=['https://book.douban.com/top250']
		def parse(self, response, **kwargs):
				print(response.text) # 测试页面

测试:

#在terminal终端进行
cd booktop # 进入项目文件夹
scrapy crawl bookspider # 运行项目下的爬虫(和name的值保持一致)
# 测试成功,看到页面代码

获取数据(书名+出版社)

 需要导入BookItem类 文件开头导入 from booktop.items import BookItem
def parse(self, response, **kwargs):
		 #print(response.text)
		# table 一个table一本书
		tables=response.xpath('//table') # css也可以
		# print('书籍个数',len(tables))
		# print(tables)
		for t in tables:
				#提取 extract()[0]
				tit=t.css('div.pl2 a::attr(title)').extract()[0]
				# print(title) 书名
				pu=t.css('p.pl::text').extract()[0]
				pu=pu.split('/')[-3].strip()
 				#print(pub) 出版社
				yield BookItem(title=tit,pub=pu)

需要使用item对象完成数据封装并传输

#items.py书写书类
class BookItem(scrapy.Item):
		#define the fields for your item here like:
		title=scrapy.Field()
		pub=scrapy.Field()
		pass

pipeline 管道存储数据

# 在setting文件下,解开注释
ITEM_PIPELINES={
'booktop.pipelines.BooktopPipeline': 300,
}

数据存储到txt文件下

# 打开管道文件 BooktopPipeline
class BooktopPipeline:
	def process_item(self, item, spider):
		# 编码格式设置为utf-8
		file=open('result.txt','a+',encoding='utf-8')
		file.write(item['title']+','+item['pub']+'\n')
		return item
# 运行测试结果result.txt下有数据成功

分析和可视化

# 在项目中创建 分析文件 demo1.py
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib
# 处理中文字体
font={'family': 'microsoft yahei',
		'weight': 'bold',
		'size': 12}
matplotlib.rc('font',**font)
# 读取文件
df=pd.read_csv('result.txt',names=['title','pub'])
# print(df)
# 福尔摩斯探案集 出版社有问题,手动修改
df.loc[8,'pub']='群众出版社'
# print(df)
# 按出版社不同分类汇总书数量,取出前5名
result=df['pub'].value_counts().head()
print(result)
plt.pie(result,labels=result.index,autopct='%3.1f%%')
plt.show()

私信小编01即可获取大量Python学习资料

在当今数字化时代,对电影的评价和反馈在很大程度上影响着人们的选择。豆瓣作为一个知名的电影评价平台,汇集了大量用户对电影的评论和评分。本文将介绍如何使用Python编写爬虫来获取豆瓣电影的影评数据,并通过情感分析对评论进行简单的情感评价。

环境准备

在开始之前,我们需要安装一些Python库来帮助我们完成这项任务:

  • requests:用于发送HTTP请求以获取网页内容。
  • Beautiful Soup:用于解析HTML网页。
  • pandas:用于数据处理和分析。
  • TextBlob:用于情感分析。

爬取豆瓣电影影评

我们首先需要确定要爬取的电影和其对应的豆瓣链接。以电影《肖申克的救赎》为例,其豆瓣链接为:https://movie.douban.com/subject/1292052/。我们将使用Python编写爬虫来获取该电影的影评数据。

pythonimport requests
from bs4 import BeautifulSoup
import pandas as pd

# 发送HTTP请求获取网页内容
url='https://movie.douban.com/subject/1292052/comments?status=P'
response=requests.get(url)
html_content=response.text

# 使用Beautiful Soup解析HTML内容
soup=BeautifulSoup(html_content, 'html.parser')

# 提取影评信息
comments=[]
for comment in soup.find_all(class_='comment-item'):
    username=comment.find(class_='comment-info').a.text.strip()
    rating=comment.find(class_='rating').attrs['title'].strip()
    content=comment.find(class_='short').text.strip()
    comments.append({'用户名': username, '评分': rating, '评论内容': content})

# 将数据转换为DataFrame
df=pd.DataFrame(comments)
print(df)

以上代码会输出一个DataFrame,其中包含了《肖申克的救赎》的影评数据,包括用户名、评分和评论内容。

情感分析

接下来,我们将使用TextBlob库进行简单的情感分析,对评论进行情感评价。

pythonfrom textblob import TextBlob

# 对评论进行情感分析
df['情感分析']=df['评论内容'].apply(lambda x: TextBlob(x).sentiment.polarity)

# 打印情感分析结果
print(df)

通过情感分析,我们可以得到每条评论的情感分数,从-1到1,其中-1表示负面情感,0表示中性,1表示积极情感。

总结

通过本文的介绍,我们了解了如何使用Python编写爬虫来获取豆瓣电影的影评数据,并通过情感分析对评论进行简单的情感评价。这项技术可以帮助大家更好地了解用户对电影的反馈和评价,为电影选择提供参考。