东京奥运会
前些天看东京奥运会的时候,18岁的突尼斯🇹🇳游泳运动员Ahmed Hafnaoui,获得男子400米自由泳冠军🏆本届奥运会爆冷选手!突尼斯只有这一个游泳运动员,还是游8道的,在最边边上,预选赛游得最慢的选手在决赛中成为第一名!
发现当他们国家国旗升起来的时候,感觉自己见都没见过;其实不光这个国家的国旗,奥运会上有好多国家的国旗我也都不认识,既然这样,今天就带大家来做一个国旗学习的网站吧,也算是给自己科普一下。
爬取网站信息存入数据库
-
在网上找了一个网站, ?里面有全世界各国国旗大全,链接如下: http://114.xixik.com/country-flag/ -
打开网站,就看到这样一个表格(如下图),心里想着这不就妥了吗, 国旗,国家,首都,人口,面积都有了,那我们直接直接这个表格岂不是可以拿到所有的信息了,当我按下F12打开谷歌浏览器的开发者工具查看的时候,发现让人有点小心塞的问题,这个表格里面的国旗竟然是缩略图,根本看不清。 -
没办法,只能再另想其他招了,再浏览浏览这个网站,发现这个表格上方还有一个表格里是有所有国家国旗的清晰图片的,并且每个国旗都有其对应的国家名称,那我们就只能先爬虫解析表格里的信息,然后根据国家名称找到对应的国旗图片链接,再一并存入我们的mysql数据库中。方便后面的网页制作。 -
网站页面简要分析 -
打开F12开发者工具获取headers - 每个浏览器都有自己的headers,因为headers要模仿你自己的浏览器向网页发送信息。 -
页面组成 -
国旗图片获取稍稍麻烦一些,先找到上面页面组成图片中展示的所有国家名称,然后根据国家名称去另一个表格里匹配到国旗图片,获取图片的链接,然后写入数据库表中 -
爬虫代码编写 #!/usr/bin/python3# -*- coding: utf-8 -*-# @Author ? : 陈龙# @公众号 ? : Python欢乐时光# @Date ? ? : 2021/08/21 12:51# @Software : PyCharm# @Version : Python 3.7.3import reimport collectionsimport pymysqlimport requestsfrom bs4 import BeautifulSoupclass CountryFlagSpider: ? def __init__(self): ? ? ? self.host = '121.4.102.161' ? ? ? self.user = 'root' ? ? ? self.password = 'cycl19940417' ? ? ? self.database = 'django_web' ? ? ? self.url = 'http://114.xixik.com/country-flag/' ? ? ? self.headers = { ? ? ? ? ? 'Host': '114.xixik.com', ? ? ? ? ? 'Connection': 'keep-alive', ? ? ? ? ? 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 ' ? ? ? ? ? ? ? ? ? ? ? ? '(KHTML, like Gecko) Chrome/92.0.4515.107 Safari/537.36' ? ? ? } ? ? ? # 用来存储我们爬取信息的字典 ? ? ? self.country_flag_list = list() ? def get_html_content(self): ? ? ? r = requests.get(self.url, headers=self.headers) ? ? ? r.encoding = 'gb2312' ? ? ? soup = BeautifulSoup(r.text, 'html.parser') ? ? ? return soup ? def get_country_info(self): ? ? ? soup = self.get_html_content() ? ? ? # 找到所有的行 ? ? ? trs = soup.findAll("div", {"class": "lindBox"})[6].findAll("tr") ? ? ? for tr in trs: ? ? ? ? ? tmp_dict = collections.OrderedDict() ? ? ? ? ? try: ? ? ? ? ? ? ? tds = tr.findAll('td')[1:] # 去除缩略图 ? ? ? ? ? ? ? tmp_dict['name'] = tds[0].text.strip() # 国家名称 ? ? ? ? ? ? ? tmp_dict['capital'] = tds[1].text.strip() # 国家首都 ? ? ? ? ? ? ? tmp_dict['population'] = tds[2].text.strip() # 国家人口 ? ? ? ? ? ? ? tmp_dict['area'] = tds[3].text.strip() # 国家面积 ? ? ? ? ? ? ? self.country_flag_list.append(tmp_dict) ? ? ? ? ? except Exception as e: ? ? ? ? ? ? ? print(e) ? def get_country_picture(self): ? ? ? soup = self.get_html_content() ? ? ? tds = soup.findAll("div", {"class": "lindBox"})[5].findAll("td") ? ? ? for td in tds: ? ? ? ? ? try: ? ? ? ? ? ? ? picture_url = td.find('img')['src'] ? ? ? ? # 获取国旗图标的src ? ? ? ? ? ? ? # 利用正则匹配字符串中的所有中文字符, '[\u4e00-\u9fa5]' 匹配中文 ? ? ? ? ? ? ? country_name = ''.join(re.findall(r'[\u4e00-\u9fa5]', td.text.strip())) # 获取国旗图标对应的名称 ? ? ? ? ? ? ? for each in self.country_flag_list: ? ? ? ? ? ? ? ? ? if each['name'] == country_name: ? ? ? ? ? ? ? ? ? ? ? each['picture'] = picture_url ? ? ? ? ? ? ? ? ? ? ? break ? ? ? ? ? except Exception as e: ? ? ? ? ? ? ? pass ? def save_into_db(self): ? ? ? self.get_country_info() ? ? ? self.get_country_picture() ? ? ? db = DbHelper(self.host, self.user, self.password, self.database) ? ? ? for each in self.country_flag_list: ? ? ? ? ? sql = 'insert into country_flag_info(name, capital, population, area, picture) values(%s, %s, %s, %s, %s)' ? ? ? ? ? values = list(each.values()) ? ? ? ? ? while len(values) < 5: ? ? ? ? ? ? ? values.append('') ? ? ? ? ? db.insert(sql, values) ? ? ? db.close()class DbHelper: ? def __init__(self, host, user, password, database): ? ? ? # 连接database ? ? ? self.conn = pymysql.connect(host=host, user=user, password=password, database=database, charset='utf8') ? ? ? # 得到一个可以执行SQL语句的光标对象 ? ? ? self.cursor = self.conn.cursor() ? def insert(self, sql, *args): ? ? ? try: ? ? ? ? ? # 执行SQL语句 ? ? ? ? ? self.cursor.execute(sql, *args) ? ? ? ? ? # 提交事务 ? ? ? ? ? self.conn.commit() ? ? ? except Exception as e: ? ? ? ? ? # 有异常,回滚事务 ? ? ? ? ? self.conn.rollback() ? def delete(self, sql, *args): ? ? ? try: ? ? ? ? ? # 执行SQL语句 ? ? ? ? ? self.cursor.execute(sql, *args) ? ? ? ? ? # 提交事务 ? ? ? ? ? self.conn.commit() ? ? ? except Exception as e: ? ? ? ? ? # 有异常,回滚事务 ? ? ? ? ? self.conn.rollback() ? def update(self, sql, *args): ? ? ? try: ? ? ? ? ? # 执行SQL语句 ? ? ? ? ? self.cursor.execute(sql, *args) ? ? ? ? ? # 提交事务 ? ? ? ? ? self.conn.commit() ? ? ? except Exception as e: ? ? ? ? ? # 有异常,回滚事务 ? ? ? ? ? self.conn.rollback() ? def query(self, sql, *args): ? ? ? # 执行SQL语句 ? ? ? self.cursor.execute(sql, *args) ? def close(self): ? ? ? self.cursor.close() ? ? ? self.conn.close()if __name__ == '__main__': ? obj = CountryFlagSpider() ? obj.save_into_db()
执行完上述代码后,网站上我们需要的数据就已经被我存储到mysql数据库中了,结果如下图
创建Django + Vue 的web网站
django创建项目及在服务器上mysql下载安装和配置在上一篇的公众号文章 从零开始在云服务器上搭建Django项目 中已经讲过了,如还没配置,请参照上一篇教程
安装node.js
-
新建一个文件夹 mkdir node -
下载 wget https://npm.taobao.org/mirrors/node/v14.15.4/node-v14.15.4-linux-x64.tar.xz -
解压 tar -xvf node-v14.15.4-linux-x64.tar.xz -
重命名 mv node-v14.15.4-linux-x64 nodejs -
建立软连接 ln -s /node/nodejs/bin/npm /usr/bin/npm ln -s /node/nodejs/bin/node /usr/bin/node -
查看 node -v npm -v -
添加淘宝镜像 npm config set registry https://registry.npm.taobao.org -
查看修改结果 npm config get registry
安装 vue
数据库同步
前端主要代码
<template> ?<div id="app"> ? ?<div class="line"></div> ? ?<el-menu ? ? ?:default-active="activeIndex" ? ? ?class="el-menu-demo" ? ? ?mode="horizontal" ? ? ?@select="handleSelect" ? ? ?background-color="#545c64" ? ? ?text-color="#fff" ? ? ?active-text-color="#ffd04b"> ? ? ?<el-menu-item index="1">近期小制作</el-menu-item> ? ? ?<el-menu-item index="2"><a href="https://blog.csdn.net/sky5601" target="_blank">我的博客</a></el-menu-item> ? ?</el-menu> ? ?<el-tabs v-model="activeName" type="card" @tab-click="handleClick"> ? ? ?<el-tab-pane label="国旗常识学习" name="first"> ? ? ? ?<el-container> ? ? ? ? ?<el-header> ? ? ? ? ? ?<!-- <p>微信公众号:Python欢乐时光<p> --> ? ? ? ? ? ?<p>国旗常识在线学习<p> ? ? ? ? ?</el-header> ? ? ? ? ?<el-main> ? ? ? ? ? ?<div class="img_div" style="text-align: center;"> ? ? ? ? ? ? ?<el-image :src="src"></el-image> ? ? ? ? ? ?</div> ? ? ? ? ? ?<div style="text-align:center;margin:20px"> ? ? ? ? ? ? ?<el-button type="success" round @click="btn_show_detail">{{ btn_msg }}</el-button> ? ? ? ? ? ?</div> ? ? ? ? ? ?<div class="table_div"> ? ? ? ? ? ? ? ?<table class="ruletable" v-show="table_show"> ? ? ? ? ? ? ? ? ?<tbody> ? ? ? ? ? ? ? ? ? ? ?<tr> ? ? ? ? ? ? ? ? ? ? ? ? ?<td>国家:</td> ? ? ? ? ? ? ? ? ? ? ? ? ?<td>{{ content[0] }}</td> ? ? ? ? ? ? ? ? ? ? ?</tr> ? ? ? ? ? ? ? ? ? ? ?<tr> ? ? ? ? ? ? ? ? ? ? ? ? ?<td>首都:</td> ? ? ? ? ? ? ? ? ? ? ? ? ?<td>{{ content[1] }}</td> ? ? ? ? ? ? ? ? ? ? ?</tr> ? ? ? ? ? ? ? ? ? ? ?<tr> ? ? ? ? ? ? ? ? ? ? ? ? ?<td>人口:</td> ? ? ? ? ? ? ? ? ? ? ? ? ?<td>{{ content[2] }}</td> ? ? ? ? ? ? ? ? ? ? ?</tr> ? ? ? ? ? ? ? ? ? ? ?<tr> ? ? ? ? ? ? ? ? ? ? ? ? ?<td>面积</td> ? ? ? ? ? ? ? ? ? ? ? ? ?<td>{{ content[3] }}</td> ? ? ? ? ? ? ? ? ? ? ?</tr> ? ? ? ? ? ? ? ? ?</tbody> ? ? ? ? ? ? ? ?</table> ? ? ? ? ? ?</div> ? ? ? ? ?</el-main> ? ? ? ? ?<el-footer> ? ? ? ? ? ?<div style="text-align:center"> ? ? ? ? ? ? ?<el-button-group> ? ? ? ? ? ? ? ?<el-button type="primary" icon="el-icon-arrow-left" @click="func_prev_page">上一个</el-button> ? ? ? ? ? ? ? ?<el-button type="primary" @click="func_next_page">下一个<i class="el-icon-arrow-right el-icon--right"></i></el-button> ? ? ? ? ? ? ?</el-button-group> ? ? ? ? ? ? ?<p style="margin-top:20px">By 微信公众号:Python欢乐时光<p> ? ? ? ? ? ?</div> ? ? ? ? ?</el-footer> ? ? ? ?</el-container> ? ? ?</el-tab-pane> ? ? ?<el-tab-pane label="车标常识学习" name="second">功能正在开发中, 敬请期待</el-tab-pane> ? ? ?<el-tab-pane label="天气查询" name="third">功能正在开发中, 敬请期待</el-tab-pane> ? ? ?<el-tab-pane label="功能待开发" name="fourth" disabled>功能待开发</el-tab-pane> ? ?</el-tabs> ?</div></template><script>export default { ?data () { ? ?return { ? ? ?init_id: 1, ? ? ?content:['', '', '', ''], ? ? ?btn_msg:'查看详情', ? ? ?flag:0, ? ? ?table_show:false, ? ? ?tableData:[], ? ? ?activeIndex: '1', ? ? ?activeName: 'first', ? ? ?src: '' ? } }, ?mounted() { ? ?// document.title = '微信公众号搜索:Python欢乐时光' ? ?this.my_func(this.init_id) }, ?methods: { ? ?my_func: function(id) { ? ? ?let that = this ? ? ?this.axios({ ? ? ? ?url: '/country_flag', ? ? ? ?method: 'get', ? ? ? ?params: { ? ? ? ? ?'id':id ? ? ? } ? ? }).then(res => { ? ? ? ?let res_data = res.data[0].fields ? ? ? ?console.log([res_data.name, res_data.capital, res_data.population, res_data.area]) ? ? ? ?that.content = [res_data.name, res_data.capital, res_data.population, res_data.area] ? ? ? ?console.log(res_data.picture) ? ? ? ?that.src = res_data.picture ? ? }).catch(err => { ? ? ? ?console.log(err) ? ? }) ? }, ? ?handleSelect(key, keyPath) { ? ? ?console.log(key, keyPath) ? }, ? ?handleClick(tab, event) { ? ? ?console.log(tab, event) ? }, ? ?func_prev_page() { ? ? ?if (this.init_id == 1) { ? ? ? ?this.init_id = 191 ? ? } else { ? ? ? ?this.init_id = this.init_id - 1 ? ? } ? ? ?this.my_func(this.init_id) ? }, ? ?func_next_page() { ? ? ?if (this.init_id === 191) { ? ? ? ?this.init_id = 1 ? ? } else { ? ? ? ?this.init_id = this.init_id + 1 ? ? } ? ? ?this.my_func(this.init_id) ? }, ? ?btn_show_detail() { ? ? ?if (this.flag === 0) { ? ? ? ?this.btn_msg = '隐藏详情' ? ? ? ?this.flag = 1 ? ? ? ?this.table_show = true ? ? } else { ? ? ? ?this.btn_msg = '查看详情' ? ? ? ?this.flag = 0 ? ? ? ?this.table_show = false ? ? } ? } }}</script><style>body { ?font-family: Helvetica, sans-serif;}p { ?font-size: 20px; ?text-align: center;}.img_div { ?padding-left:20%; ?padding-right:20%;}.table_div { ?padding-left:20%; ?padding-right:20%;}.ruletable{ ?width: 100%; ?border-collapse: collapse;}.ruletable th{ ?text-align: center;}.ruletable tr:nth-of-type(1){ ?border-top: 1px solid #FFDCDF;}.ruletable tr{ ?border-bottom: 1px solid #FFDCDF;}</style>
后端主要代码
# views.py 中class country_flag(APIView): ? ?def get(self,request): ? ? ? ?query_id = request.GET["id"] ? ? ? ?data = serializers.serialize("json", CountryFlagInfo.objects.filter(id=query_id)) ? ? ? ?return HttpResponse(data, content_type='application/json') ? ?# models.py 中class CountryFlagInfo(models.Model): ? ?name = models.CharField(max_length=50, db_collation='utf8_general_ci', blank=True, null=True) ? ?capital = models.CharField(max_length=50, db_collation='utf8_general_ci', blank=True, null=True) ? ?population = models.CharField(max_length=50, db_collation='utf8_general_ci', blank=True, null=True) ? ?area = models.CharField(max_length=50, db_collation='utf8_general_ci', blank=True, null=True) ? ?picture = models.TextField(blank=True, null=True) ? ?class Meta: ? ? ? ?managed = False ? ? ? ?db_table = 'country_flag_info'
完整的项目代码请在公众号下方回复 国旗 获取下载地址
最终效果演示
在电脑或者手机的浏览器中输入:http://121.4.102.161:8000/
PS: 由于我购买的服务器配置是最低的(别问我为什么不买配置高的,问就一个字,因为穷…),所以访问的时候可能会有些慢,请耐心等待几秒钟即可。见谅!
电脑端访问效果
手机端访问效果
结尾
如果觉得这篇文章还不错的话,欢迎点击文章右下角的“在看”, 期待您关注我的公众号 Python欢乐时光 ,转发给你身边有需要的朋友们。另外,本篇文章中所有的项目代码我都打包上传至百度网盘,公众号下方回复 国旗 获取下载地址。谢谢大家!
|