前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >如何将豆瓣观影记录实时同步至博客中

如何将豆瓣观影记录实时同步至博客中

作者头像
Meng小羽
修改于 2020-06-08 02:33:14
修改于 2020-06-08 02:33:14
96000
代码可运行
举报
文章被收录于专栏:Debug客栈Debug客栈
运行总次数:0
代码可运行

友情提示:此篇文章大约需要阅读 27分钟32秒,不足之处请多指教,感谢你的阅读。👉 订阅本站

事情的起因是这样的,前几日在看 idealclover 大佬的博客,不经意间看到了他的豆瓣观影记录,他博客中关于豆瓣观影记录是实时同步的,很好奇是如何实现的,经过查看,他是爬取的豆瓣观影界面来实现的,其实关于豆瓣观影记录,网上也有很多的教程,恰巧自己所学的 Go 语言也可以做简单的爬虫实现其效果,于是开始上手造轮子了,PS:了解到非法爬取网站信息是违法的,之前豆瓣 API 接口,关闭访问,在豆瓣上找了好久,终于在我的主页中找到了对于观影记录的官方提供 RSS 订阅,打开订阅,看到有自己所需要的字段,比较好获取,于是就开始了此项目。

分析

首先,需要获取豆瓣提供的 XML 文件,在我的主页右下角就可以看到 RSS 订阅链接:

豆瓣订阅地址

找到了订阅地址,点击查看 XML 结构,可以看到豆瓣提供的结构还是挺理想的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" version="2.0">
<channel>
    <title>Meng小羽 的收藏</title>
    <link>https://www.douban.com/people/debuginn/</link>
    <description>
        <![CDATA[ Meng小羽 的收藏:想看、在看和看过的书和电影,想听、在听和听过的音乐 ]]>
    </description>
    <language>zh-cn</language>
    <copyright>© 2013, douban.com.</copyright>
    <pubDate>Sat, 30 May 2020 09:14:08 GMT</pubDate>
    <item>
        <title>看过黑衣人:全球追缉</title>
        <link>http://movie.douban.com/subject/19971676/</link>
        <description>
        <![CDATA[ <table><tr> <td width="80px"><a href="https://movie.douban.com/subject/19971676/" title="Men in Black International"> <img src="https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2558701068.webp" alt="Men in Black International"></a></td> <td> <p>推荐: 力荐</p> </td></tr></table> ]]>
        </description>
        <dc:creator>Meng小羽</dc:creator>
        <pubDate>Sat, 30 May 2020 09:14:08 GMT</pubDate>
        <guid isPermaLink="false">https://www.douban.com/people/debuginn/interests/2402808825</guid>
    </item>
    ......
<channel>

其实,我们提取的主要就是 item 标签下对应的电影信息内容:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<item>
    <title>看过黑衣人:全球追缉</title>
    <link>http://movie.douban.com/subject/19971676/</link>
    <description>
    <![CDATA[ <table><tr> <td width="80px"><a href="https://movie.douban.com/subject/19971676/" title="Men in Black International"> <img src="https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2558701068.webp" alt="Men in Black International"></a></td> <td> <p>推荐: 力荐</p> </td></tr></table> ]]>
    </description>
    <dc:creator>Meng小羽</dc:creator>
    <pubDate>Sat, 30 May 2020 09:14:08 GMT</pubDate>
    <guid isPermaLink="false">https://www.douban.com/people/debuginn/interests/2402808825</guid>
</item>

设计

根据豆瓣官方提供的 XML 标签数据,可以利用 Go 语言中 encoding/xml 包来进行对数据的映射,可以设计成如下结构体:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 豆瓣 xml 描述结构体
type Attributes struct {
	XMLName xml.Name `xml:"rss"`
	Version string   `xml:"version,attr"`
	Channel Channel  `xml:"channel"`
}

// XML 主题结构拆分
type Channel struct {
	Title       string      `xml:"title"`
	Link        string      `xml:"link"`
	Description string      `xml:"description"`
	Language    string      `xml:"language"`
	Copyright   string      `xml:"copyright"`
	Pubdate     string      `xml:"pubDate"`
	MovieItem   []MovieItem `xml:"item"`
}

// 豆瓣 电影列表结构体
type MovieItem struct {
	Title       string `xml:"title"`
	Link        string `xml:"link"`
	Description string `xml:"description"`
	Pubdate     string `xml:"pubDate"`
}

可以和 XML 文件对应字段进行匹配,可以从上面的结构体中我们可以看到,最终我们想获取到的数据就是结构体 MovieItem 的数据。

由于是从网上链接获取数据的,在这里首先我们需要将网上豆瓣提供的 XML 文件转换成 []byte 类型的数据:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 获取 xml 文件数据
func getXMLData(url string) (data []byte, err error) {
	// 读取 xml 文件
	client := &http.Client{}
	req, _ := http.NewRequest("GET", url, nil)
	// 自定义Header
	req.Header.Set("User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1)")
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close() // 关闭文件
	// 读取所有文件内容保存至 []byte
	data, err = ioutil.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}
	return
}

上面这个函数实现的就是将 XML 文件保存至 Go 语言的数据结构的操作,现在可以将 XML 文件成功读取出来,接下来就是要进行 XML 字段与上面作出的结构体之间的映射,其实映射至结构体的过程是比较简单的,首先声明 Attributes{} 类型的结构体,之后通过 xml.Unmarshal 来实现映射拷贝,就可以得到对应的结构体类型的数据,由于我们想要的数据是结构体数据中的一部分,即 MovieItem,在得到结构体数据后就可以将想要的这一部分的数据选择抽取出来:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
v := Attributes{}
unMarshalErr := xml.Unmarshal(data, &v)
if unMarshalErr != nil {
	fmt.Printf("xml unmarshal failed, err:%v\n", err)
}

movieItem := v.Channel.MovieItem

Map 转换

在这里我们可以得到结构体中嵌套的结构体,在结构体中有一些字段我们是不想要的,需要进行处理,对于 description 这个字段中,官方提供的是一段 HTML 描述串,其中电影的描述文件是我们所需要的,对于 HTML 字符串的拆分,我们可以借助strings.Split 函数来实现截取,使用 \" 符号截取,虽然可以获取到我们想要的数据了,但是由于这个是嵌套的结构体,我们需要做一个匹配的 map 来进行存储处理好的数据,可以看代码中我的设计:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
MoviesMap := make(map[int]interface{})
for i := 0; i < len(movieItem); i++ {
	movie := make(map[string]string)
	description := strings.Split(movieItem[i].Description, "\"")
	movie["Title"] = string([]rune(movieItem[i].Title)[2:])
	movie["Link"] = movieItem[i].Link
	movie["Img"] = description[7]
	movie["Pubdate"] = movieItem[i].Pubdate

	MoviesMap[i] = movie
}

外层 map 是采用 map[int]interface{} 类型,在 interface{} 中存储这内层 map map[string]string 类型。

针对于 Img 地址的获取,是现根据特定符号拆分,之后获取制定位置的数据获取的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
0 map[Img:https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2558701068.jpg Link:http://movie.douban.com/subject/19971676/ Pubdate:Sat, 30 May 2020 09:14:08 GMT Title:黑衣人:全球追缉]
1 map[Img:https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2263408369.jpg Link:http://movie.douban.com/subject/1294371/ Pubdate:Thu, 28 May 2020 10:06:23 GMT Title:摩登时代]
......

最后就是将这个 map 做一下序列化处理,这样就可以返回给前台数据了。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
data, _ = json.Marshal(MoviesMap)

服务

处理好数据,做了对应的处理,怎么将数据作为服务端提供给前台,在这里需要使用 Web 服务,Go 中可以使用原生 Web,不过我在这里使用的是之前学过的 Gin 框架,来提供服务的:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
r := gin.Default()
r.GET("/doubanmovies", func(context *gin.Context) {
	context.JSON(http.StatusOK, MoviesMap)
})
_ = r.Run(":8080")

api json数据

启动服务,可以得到对应的 json 数据,你若以为现在就可以实现了,那么你错了,远远没有那么简单……

前台

由于我知晓我的博客采用的前台 UI 技术是 MDUI, 我利用自身的卡片 UI 迅速设计了一个模块,因为后期需要放在我的博客页面上,前端读取数据采用的是 VUE 和 axios 技术:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<div class="mdui-container-fluid" id="app">
    <div class="mdui-row">
        <div v-for="item in info">
            <div class="mdui-col-xs-6 mdui-col-sm-4 mdui-col-md-3 mdui-col-lg-3 mdui-m-b-1 mdui-m-t-1">
                <a :href="item.Link" target="_blank">
                    <div class="mdui-card mdui-hoverable">
                        <div class="mdui-card-media">
                            <img :src="item.Img" style="height: 260px;" />
                            <div class="mdui-card-media-covered">
                                <div class="mdui-card-primary">
                                    <div class="mdui-card-primary-subtitle">{{ item.Title }}</div>
                                </div>
                            </div>
                        </div>
                    </div>
                </a>
            </div>
        </div>
    </div>
</div>
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<script src="./static/js/mdui.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.8/vue.min.js"></script>
<script src="https://cdn.staticfile.org/axios/0.18.0/axios.min.js"></script>
<script>
    new Vue({
        el: '#app',
        data() {
            return {
                info: null
            }
        },
        mounted() {
            axios
                .get('http://127.0.0.1:8080/doubanmovies')
                .then(response => (this.info = response.data))
                .catch(function (error) { // 请求失败处理
                    console.log(error);
                });
        }
    })
</script>

设计好了以后,访问页面,却加载不出来,emmmmmm

CORS

CORS

看到了是 CORS 同源策略的原因,接下来就是要解决同源问题了,方法比较简单,就是将 Go 服务端加上 CORS 同源策略就可以了,方法如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
r := gin.Default()
r.Use(Cors())
r.GET("/doubanmovies", func(context *gin.Context) {
	context.JSON(http.StatusOK, MoviesMap)
})

_ = r.Run(":8080")

路由访问中添加 Cors() 函数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 跨域
func Cors() gin.HandlerFunc {
	return func(c *gin.Context) {
		method := c.Request.Method               //请求方法
		origin := c.Request.Header.Get("Origin") //请求头部
		var headerKeys []string                  // 声明请求头keys
		for k, _ := range c.Request.Header {
			headerKeys = append(headerKeys, k)
		}
		headerStr := strings.Join(headerKeys, ", ")
		if headerStr != "" {
			headerStr = fmt.Sprintf("access-control-allow-origin, access-control-allow-headers, %s", headerStr)
		} else {
			headerStr = "access-control-allow-origin, access-control-allow-headers"
		}
		if origin != "" {
			c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
			c.Header("Access-Control-Allow-Origin", "*")                                       // 这是允许访问所有域
			c.Header("Access-Control-Allow-Methods", "POST, GET, OPTIONS, PUT, DELETE,UPDATE") //服务器支持的所有跨域请求的方法,为了避免浏览次请求的多次'预检'请求
			//  header的类型
			c.Header("Access-Control-Allow-Headers", "Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive, User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma")
			//              允许跨域设置                                                                                                      可以返回其他子段
			c.Header("Access-Control-Expose-Headers", "Content-Length, Access-Control-Allow-Origin, Access-Control-Allow-Headers,Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma,FooBar") // 跨域关键设置 让浏览器可以解析
			c.Header("Access-Control-Max-Age", "172800")                                                                                                                                                           // 缓存请求信息 单位为秒
			c.Header("Access-Control-Allow-Credentials", "false")                                                                                                                                                  //  跨域请求是否需要带cookie信息 默认设置为true
			c.Set("content-type", "application/json")                                                                                                                                                              // 设置返回格式是json
		}

		//放行所有OPTIONS方法
		if method == "OPTIONS" {
			c.JSON(http.StatusOK, "Options Request!")
		}
		// 处理请求
		c.Next() //  处理请求
	}
}

这样就可以看到结果了,如下图:

演示

看到结果后,心中窃喜,感觉成功了,接下来就需要将 Go 服务部署到我的服务器中去了,部署步骤比较简单,就不过多解释了,最后访问服务器 IP 及对应单口可以呈现结果,最后将前台代码粘贴到新建的页面中,生成预览,emmmm,啥都没有,浏览器居然报 HTTPS 请求 HTTP 资源是不安全的,吐了一口血,解决吧,唉,经过查询资料,得出如下两个解决方案:

  • Gin 框架服务本身使用 SSL 证书,实现 HTTPS 访问,不过需要配置域名;
  • 使用 Nginx 服务做一下代理,将一个特定链接代理到本身服务中去。

作为学生党的我,没有太多的资金去申请过多的 SSL 证书(省着点用),于是我就在我的 demo.debuginn.cn 子域名下做了一个代理。

代理

Nginx 代理实现也是比较简单的,就是将前端访问某个接口代理至服务器中某个端口的服务中,表面上看是 Nginx 在做数据处理,实际上是 Nginx 只做了一个代理转发,由于我demo.debuginn.cn 子域名本身就是 https 的,所以设置好了代理之后,就可以使用固定的代理链接访问了,配置如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
server{
    .....
    location /doubanmovies {
        proxy_pass http://127.0.0.1:8080;
        proxy_set_header Host $host:80;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

这样就可以实现 https 资源访问了:https://demo.debuginn.cn/doubanmovies

效果

解决了 HTTPS 访问 HTTP 资源的问题,就解决了所有问题,实现了效果。

我的观影

具体效果如下:https://cloud.tencent.com/developer/article/1635999

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
知识分享之Golang——Gin学习之开放所有接口的OPTION方法
知识分享之Golang篇是我在日常使用Golang时学习到的各种各样的知识的记录,将其整理出来以文章的形式分享给大家,来进行共同学习。欢迎大家进行持续关注。
cn華少
2021/12/10
1.8K0
Golang快速开发框架——所有请求增加option接口便于前后端分离(九)
知识分享之Golang篇是我在日常使用Golang时学习到的各种各样的知识的记录,将其整理出来以文章的形式分享给大家,来进行共同学习。欢迎大家进行持续关注。
cn華少
2022/03/04
6020
Python爬虫——电影top榜
图片的实际是data-src,而不是src需要实际看一下请求数据返回的response值
羊羽shine
2019/05/29
5820
Golang 跨域
跨域指的是浏览器不能执行其他网站或域名下的脚本。之所以形成跨域,是因为浏览器的同源策略造成的,是浏览器对javascript程序做的安全限制,现在所有支持JavaScript 的浏览器都会使用这个策略。
孤烟
2020/09/27
1.2K0
03 . Gin+Vue开发一个线上外卖应用(用户数据创建,插入,跨域处理)
通过定义Member结构体,表示应用的用户信息。通过TAG中的xorm来指定结构体在数据库表中的约束。
iginkgo18
2020/11/12
4890
03 . Gin+Vue开发一个线上外卖应用(用户数据创建,插入,跨域处理)
用 Python 爬取豆瓣电影海报
之前写过一篇用 Python 爬取豆瓣上的图片,那今天就来写一下爬取豆瓣上的电影海报,算是姐妹篇。
伪君子
2019/03/01
1.5K0
用 Python 爬取豆瓣电影海报
从0开始,用Go语言搭建一个简单的后端业务系统
Hello 小伙伴们,今天给大家带来了一份Go语言搭建后端业务系统的教程,restful风格哦,既然是简单的业务系统,那么必要的功能就少不了增删改查,也就是传说中的CRUD,当然相比Spring Boot而言,Go语言写后端业务系统不是那么的流行,但是对比一下我们也很容易能发现,Go语言搭建的Web后端系统的优势:
闫同学
2023/10/11
5690
Python爬虫实战示例-51job和豆瓣电影
命令:conda create -n {} python={}第一对大括号替换为环境的命名,第二对大括号替换为python的版本号 例如:conda create -n python27 python=2.7 这个命令就是创建一个python版本为2.7的环境,并命名为python27
潇洒坤
2018/09/10
7660
Python爬虫实战示例-51job和豆瓣电影
Python 从底层结构聊 Beautiful Soup 4(内置豆瓣最新电影排行榜爬取案例)!
Beautiful Soup 4(简称 BS4,后面的 4 表示最新版本)是一个 Python 第三方库,具有解析 HTML 页面的功能,爬虫程序可以使用 BS4 分析页面无素、精准查找出所需要的页面数据。有 BS4 的爬虫程序爬行过程惬意且轻快。
一枚大果壳
2022/08/23
1.3K0
Python 从底层结构聊 Beautiful Soup  4(内置豆瓣最新电影排行榜爬取案例)!
Python3爬虫学习.md
(1) urllib 简单的爬取指定网站 (2) Scrapy 爬虫框架 (3) BeautifulSoup 爬虫解析
全栈工程师修炼指南
2020/10/23
8380
Python3爬虫学习.md
数据获取:​网页解析之lxml
lxml是Python的一个解析库,支持HTML和XML的解析,支持XPath(XML Path Language)解析方式。XPath,它是一门在XML文档中查找信息的语言,具有自身的语法,是用来确定XML文档中某部分位置的语言,最初是用来搜寻XML文档的,当然也适用于HTML文档的搜索。通俗点讲就是lxml可以根据XPath表示的位置来确定HTML页面中的内容,从而实现找到我们需要的内容。
马拉松程序员
2023/09/02
3840
数据获取:​网页解析之lxml
python scrapy爬虫练习(1) 爬取豆瓣电影top250信息
文章目录 一、分析网页 目标URL:https://movie.douban.com/top250?start=0&filter= 每一页有25条电影信息,总共10页。检查网页可以发现,每条电影的详细
叶庭云
2020/09/17
5.1K0
python  scrapy爬虫练习(1)   爬取豆瓣电影top250信息
[Python从零到壹] 七.网络爬虫之Requests爬取豆瓣电影TOP250及CSV存储
requests模块是用Python语言编写的、基于urllib的第三方库,采用Apache2 Licensed开源协议的http库。它比urllib更方便简洁,既可以节约大量的工作,又完全满足http测试需求。requests是一个很实用的Python库,编写爬虫和测试服务器响应数据时经常会用到,使用requests可以轻而易举的完成浏览器相关操作。功能包括:
Eastmount
2021/12/02
1.9K0
[Python从零到壹] 七.网络爬虫之Requests爬取豆瓣电影TOP250及CSV存储
数据分析入门系列教程-数据采集
前面我们一起完成了一个数据清洗的实战教程。现在,我们一起来学习数据采集的相关知识。
周萝卜
2020/09/27
1K0
数据分析入门系列教程-数据采集
go爬虫项目
github.com/PuerkitoBio/goquery包内内置了Find函数,”Find 获取当前匹配元素集中每个元素的后代,由选择器过滤。,它返回一个包含这些匹配元素的新选择对象。”
h3110_w0r1d
2024/02/19
1780
go爬虫项目
电影荒?看看豆瓣排行榜上有没有你想看的电影!
项目创建完成后可以看到在工程创建的位置有了douban文件夹,打开以后包含了上述的组件,可以使用spyder,pycharm等ide打开项目
老肥码码码
2020/01/17
8790
电影荒?看看豆瓣排行榜上有没有你想看的电影!
NeoDB API 创建观影页面
几个月之前在 长毛象联邦宇宙 里问过 NeoDB 官方有没有 API,得到肯定回答后,我就着手计划把观影页面的 API 搬到 NeoDB 了。前几天豆瓣的图片挂掉之后,加快了这一进程。 感谢豆瓣以前提供的无偿服务。不过这也印证了 SaaS 服务不可信 的观点。
eallion
2023/10/18
6270
NeoDB API 创建观影页面
Scrapy爬虫框架教程(二)-- 爬取豆瓣电影TOP250
前言 经过上一篇教程我们已经大致了解了Scrapy的基本情况,并写了一个简单的小demo。这次我会以爬取豆瓣电影TOP250为例进一步为大家讲解一个完整爬虫的流程。 工具和环境 语言:python
木制robot
2018/04/13
1.9K0
Scrapy爬虫框架教程(二)-- 爬取豆瓣电影TOP250
一篇文章入门python爬虫(需要html,css基础)
运行结果 这个运行结果是418,意思是愚人节,表示网页发现了,访问这个网页的是程序,不是人类。
GeekLiHua
2025/01/21
400
一篇文章入门python爬虫(需要html,css基础)
Python最火爬虫框架Scrapy入门与实践,豆瓣电影 Top 250 数据采集
Python爬虫框架Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架,非常出名,非常强悍。所谓的框架就是一个已经被集成了各种功能(高性能异步下载,队列,分布式,解析,持久化等)的具有很强通用性的项目模板。对于框架的学习,重点是要学习其框架的特性、各个功能的用法即可。
二爷
2020/07/22
2.4K0
Python最火爬虫框架Scrapy入门与实践,豆瓣电影 Top 250 数据采集
推荐阅读
相关推荐
知识分享之Golang——Gin学习之开放所有接口的OPTION方法
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验