1.9 实践项目——爬取学生信息

news2024/11/25 12:40:00

1. 项目简介


设计一个 Web 服务器 server.py它读取 students.txt 文件中的学生数据,以表格的形式呈现在网页上,其中 students.txt 的格式如下:

No,Name,Gender,Age
1001,张三,男,20
1002,李四,女,19
1003,王五,男,21

设计一个客户端的爬虫程序client.py它从这个网页上爬行学生的这些信息,存储到数据库中。学生数据库可以使用 Sqllite 数据库 students.db。

2. 服务器程序


服务器程序首先读取同一个目录下的 students.txt 文件,然后组成一张<table>的HTML表格用网页的形式呈现,效果如下图:


程序先检查是否有 students.txt 文件存在,如果文件存在就打开读取,读出一行的数据使用逗号分开的,因此使用 split(",") 函数拆分,然把一行数据组成在<tr>...</tr>的行中,把每个数据组织在<td>...</td>的单元格中

服务器程序server.py 如下:

importflask
importos
​
app=flask.Flask(__name__)
​
​
@app.route("/")
defshow():
    ifos.path.exists("students.txt"):
        st="<h3>学生信息表</h3>"
        st=st+"<table border='1' width='300'>"
        fobj=open("students.txt", "rt", encoding="utf-8")
        whileTrue:
            s=fobj.readline().strip("\n")  # 读取一行,去除行尾部"\n"换行符号
            ifs=="":  # 如果读到文件尾部就退出
                break
            s=s.split(",")  # 按逗号拆分开
            st=st+"<tr>"
            foriinrange(len(s)):  # 把各个数据组织在<td>...</td>的单元格中
                st=st+"<td>"+s[i] +"</td>"
            st=st+"</tr>"  # 完成一行
        fobj.close()
        st=st+"</table>"
        returnst
​
​
if__name__=="__main__":
    app.run()
​

运行服务器程序,默认网址为 http://127.0.0.1:5000/ 。

3. 客户端程序


客户端程序访问网址 http://127.0.0.1:5000/,从中下载其 HTML 网页,这个网页的结果如下:

<h3>学生信息表</h3>
<tableborder='1'width='300'>
    <tr>
        <td>No</td>
        <td>Name</td>
        <td>Gender</td>
        <td>Age</td>
    </tr>
    <tr>
        <td>1001</td>
        <td>张三</td>
        <td>男</td>
        <td>20</td>
    </tr>
    <tr>
        <td>1002</td>
        <td>李四</td>
        <td>女</td>
        <td>19</td>
    </tr>
    <tr>
        <td>1003</td>
        <td>王五</td>
        <td>男</td>
        <td>21</td>
    </tr>
</table>

程序要从这个 HTML 网页爬取数据,只要分解出第一行:

<tr><td>No</td><td>Name</td><td>Gender</td><td>Age</td></tr>

再次分解这一行的<td>...</td>数据,就知道这个表有哪些标题字段,这个表目前有 No、Name、Gender、Age 字段。

接下来再次分解出下一行的<tr>...</tr>数据:

<tr><td>1001</td><td>张三</td><td>男</td><td>20</td></tr>

再次分解这一行的<td>...</td>数据,得到 No、Name、Gender、Age 的数据依次是 "1001"、"张三"、"男"、"20",把这一行的数据写入对应的数据库即可。

要分解出<tr>...</tr>只要使用 r"<tr>"r"/tr" 的正则表达式即可,先用 r"<tr>" 匹配 HTML 代码,得到第一个 <tr> 的位置,再使用 r"</tr>" 匹配 HTML 字符串,得到第一个 </tr> 的位置,取出 <tr>...</tr> 的数据部分,再次使用 r"<td>" 与 r"</td>" 的正则表达式分解<td>...</td> 的数据。

客户端程序client.py 如下:

importurllib.request
importre
importsqlite3
​
​
# 在html中查找学生信息
defsearchWeb(html):
    rows= []
    # 查询第一个<tr>...</tr>行
    m=re.search(r"<tr>", html)
    n=re.search(r"</tr>", html)
    ifmisnotNoneandnisnotNone:
        # 跳过第一行的标题
        html=html[n.end():]
    # 查询第二行开始的数据部分
    m=re.search(r"<tr>", html)
    n=re.search(r"</tr>", html)
    whilemisnotNoneandnisnotNone:
        row= []
        start=m.end()  # start是<tr>的结束位置
        end=n.start()  # end是</tr>的开始位置
        t=html[start:end]  # t 是<tr>...</tr>包含的字符串
        html=html[n.end():]  # 是剩余的html
        # 查询第一组<td>...</td>
        a=re.search(r"<td>", t)
        b=re.search(r"</td>", t)
        whileaisnotNoneandbisnotNone:
            start=a.end()  # start是<td>的结束位置
            end=b.start()  # end是</td>的开始位置
            row.append(t[start:end])  # 找到一组<td>...</td>的数据
            t=t[b.end():]  # 本行剩余的部分
            a=re.search(r"<td>", t)
            b=re.search(r"</td>", t)
        # 增加一行数据
        rows.append(row)
        # 继续查找下一行<tr>...</tr>
        m=re.search(r"<tr>", html)
        n=re.search(r"</tr>", html)
    returnrows
​
​
# 保存学生信息到数据库
defsaveDB(rows):
    iflen(rows) ==0:  # 没有数据就返回
        return
    try:
        con=sqlite3.connect("students.db")
        cursor=con.cursor()
        try:
            cursor.execute("drop table students")  # 如果有students表就删除
        except:
            pass
        try:
            # 建立新的students表
            sql="create table students (No varchar(128) primary key,Name varchar(128),Gender varchar(128),Age int)"
            cursor.execute(sql)
        except :
            pass
​
        forrowinrows:
            iflen(row) ==4:
                # 插入一条记录
                sql="insert into students (No,Name,Gender,Age) values (?,?,?,?)"
                try:
                    No, Name, Gender, Age=row[0], row[1], row[2], int(row[3])
                    cursor.execute(sql, (No, Name, Gender, Age))
                exceptExceptionaserr:
                    print(err)
        con.commit()  # 数据库提交保存
        con.close()
    exceptExceptionaserr:
        print(err)
​
​
# 显示查找的信息
defshowWeb(rows):
    print("显示来自Web的数据...")
    forrowinrows:
        print(row)
​
​
# 显示数据库的数据
defshowDB():
    print("显示来自DB的数据...")
    try:
        con=sqlite3.connect("students.db")
        cursor=con.cursor()
        cursor.execute("select * from students")  # 查询数据库记录
        rows=cursor.fetchall()
        # 显示每条记录
        forrowinrows:
            print(row)
        con.close()
    exceptExceptionaserr:
        print(err)
​
​
try:
    url="http://127.0.0.1:5000"
    resp=urllib.request.urlopen(url)  # 访问这个网址获取 html
    data=resp.read()
    html=data.decode()
    rows=searchWeb(html)  # 在html中查找学生信息
    showWeb(rows)  # 显示查找的信息
    saveDB(rows)  # 保存学生信息到数据库
    showDB()  # 显示数据库的数据
exceptExceptionaserr:
    print(err)
​

程序执行后结果显示客户端从服务器的网页上爬取了学生信息并保存到来数据库:

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

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

相关文章

【Junit5】就这篇,带你从入门到进阶

目录 前言 1.前置工作 2、注解 2、断言&#xff08;Assertions类&#xff09; 2.1、断言 匹配/不匹配 2.2、断言结果 为真/为假 2.3、断言结果 为空/不为空 3、用例的执行顺序 3.1、用例执行顺序是怎样的&#xff1f; 3.2、通过order注解来排序 4、参数化 4.1、单…

Firefox 110, Chrome 110, Chromium 110 官网离线下载 (macOS, Linux, Windows)

Mozilla Firefox, Google Chrome, Chromium, Apple Safari 请访问原文链接&#xff1a;https://sysin.org/blog/chrome-firefox-download/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;www.sysin.org 天下只剩三种&#xff08;主流&am…

feign技巧 - form方式传值

feign技巧 - form方式传值。 0. 文章目录1. 前言2. 调用样例3. 原理解析3.1 feign端序列化参数3.2 SpringMVC服务端解析参数3.3 补充 - 继承关系不会被传递的原因3.4 补充 - 不能使用GET。4. 总结1. 前言 直接正题。 如何使用feign进行fom表单方式的请求调用&#xff0c;以及其…

leaflet 上传KMZ文件,并在map上显示(062)

第062个 点击查看专栏目录 本示例的目的是介绍演示如何在vue+leaflet中本地上传包kmz文件,解析并在地图上显示图形。在制作本示例的过程中,还有点缺憾,就是kmz中的图片文件没有在jszip中处理好,只能先解压缩后,将图片文件放到public/文件加下,暂时留一个遗憾点,以后再做…

又发现一个ChatGPT体验站,辅助写代码真方便

♥️ 作者&#xff1a;Hann Yang ♥️ 主页&#xff1a;CSDN主页 ♥️ 2022博客之星Top58&#xff0c;原力榜Top10/作者周榜Top13 ♥️ “抢走你工作的不会是 AI &#xff0c;而是先掌握 AI 能力的人” ChatGPT 美国OpenAI研发的聊天机器人程序&#xff0c;于2022年11月30日发…

【刷题笔记】--两数之和Ⅳ,从二叉树中找出两数之和

法一&#xff1a;深度搜索中序遍历双指针 思路&#xff1a;通过中序遍历二叉树得到一个递增的数列&#xff0c;再在这个递增的二叉树中找到这两数。 主要学到双指针这个方法。 对于一般数列&#xff0c;我们要找到两数满足其之和等于目标数&#xff0c;我们一般会进行暴力&a…

C++请求SpringBoot的接口问题记录

问题描述最近忙一个小东西&#xff0c;遇到一个很有意思的问题&#xff0c;记录一下。 需求非常简单&#xff0c;就是java侧提供一个接口给C侧调用。 接口按照业务规范提供出来了&#xff0c;在postman中请求一下&#xff0c;出入参都正常。 关于这个接口请求方式为postJson方式…

C++:提高篇: 栈-寄存器和函数状态:栈指针帧指针详解

栈指针和帧指针前言1、EBP和ESP详解2、push &#xff0c;leave &#xff0c;call汇编指令分析3、下面用一个图总结前言 &#x1f697;&#x1f697;&#x1f697;&#xff1a;在刚接触 ESP和EBP概念时&#xff0c;我一直认为&#xff1a;ESP指向栈顶指针&#xff0c;EBP指向栈…

为什么说百度下个月推出文心一言会被ChatGPT完全碾压

作者&#xff0c;姚远&#xff1a; Oracle ACE&#xff08;Oracle和MySQL数据库方向&#xff09;华为云MVP 《MySQL 8.0运维与优化》的作者中国唯一一位Oracle高可用大师拥有包括 Oracle 10g和12c OCM在内的20数据库相关认证。曾任IBM公司数据库部门经理现在一家第三方公司任首…

操作系统——2.操作系统的特征

这篇文章&#xff0c;我们来讲一讲操作系统的特征 目录 1.概述 2.并发 2.1并发概念 2.1.1操作系统的并发性 3.共享 3.1共享的概念 3.2共享的方式 4.并发和共享的关系 5.虚拟 5.1虚拟的概念 5.2虚拟小结 6.异步 6.1异步概念 7.小结 1.概述 上一篇文章&#xff0c;我们…

实时数据仓库

1 为什么选择kafka? ① 实时写入&#xff0c;实时读取 ② 消息队列适合&#xff0c;其他数据库受不了 2 ods层 1&#xff09;存储原始数据 埋点的行为数据 (topic &#xff1a;ods_base_log) 业务数据 (topic &#xff1a;ods_base_db) 2&#xff09;业务数据的有序性&#x…

论文阅读 - Early Detection of Fake News by Utilizing the Credibility of News

论文链接&#xff1a;https://arxiv.org/pdf/2012.04233.pdf 目录 摘要 1 简介 2 相关工作 2.1 基于特征的方法 2.2 深度学习方法 3 问题表述 4 拟议的框架 4.2 用户可信度预测 4.3 虚假新闻分类 4.3.1 新闻内容表示 4.3.2 融合注意力单元 5 实验 5.1 数…

工厂模式--设计模式

分类&#xff1a; 1、简单工厂&#xff1a;可根据自变量的不同返回不同类的实例 应用&#xff1a;将类名和类的全路径放入到配置文件&#xff0c;通过文件流将内容读取放入到map集合中保存&#xff0c;通过反射读取类全路径读取到该类&#xff0c;然后调用类方法。 详细设计&…

山东大学2022算法期末

接力&#xff1a;山东大学2021算法期末 2022 SDU算法导论期末考试 2020 计科 计算题 三道 35’ (1) 画BFS树 (2) 做DFS说明各种边的分类使用floyd或者矩阵乘法求全源最短路&#xff0c;求最短路矩阵以及前驱矩阵&#xff08;3个点&#xff0c;比较友好&#xff0c;应该没有…

idea推送镜像到desktop报错:Cannot run program “docker-credential-desktop“ 系统找不到指定的文件。

windows Docker 搭建仓库 打开docker desktop 。 打开windows cmd窗口或powershell窗口。 输入"docker run -d -p 5000:5000 --name test registry:2 "运行一个名字叫test的registry容器。 idea配置springboot项目的docker插件 在pom.xml中的plugins中加入下面代码…

Kaldi语音识别技术(五) ----- 特征提取

Kaldi语音识别技术(五) ----- 特征提取 文章目录Kaldi语音识别技术(五) ----- 特征提取一、识别流程二、MFCC特征提取概述三、文件格式文件格式说明提取部分数据修复提取数据提取剩余部分数据四、特征提取特征提取—C特征提取—并行提取特征提取—特征查看五、CMVNCMVN—脚本CM…

SpringMVC执行流程(面试题)

SpringMVC是Spring框架中的组成成员之一&#xff0c;是一个针对于Web开发的一个类似于Servlet技术的一个web应用框架&#xff0c;它包含了MVC架构的特点&#xff0c;让Web变得更加简单。在SpringMVC框架中&#xff0c;一个比较核心的组件就是他的前端控制器&#xff0c;这个前端…

sql复习(子查询、创建和管理表)

一、子查询 子查询 (内查询) 在主查询之前一次执行完成 子查询的结果被主查询(外查询)使用 1.单行子查询 只返回一行&#xff0c;使用单行比较操作符。 --谁的工资比Able高&#xff1f; select last_name,salary from employees where salary > (select salaryfrom empl…

idea插件生成dao类service类controller类以及mapper.xml

idea插件生成dao类service类controller类以及mapper.xml 安装插件Easycode和MybatisX&#xff0c;不用自己写代码 1.Files——》Settings——》Plugins&#xff0c;分别搜索Easycode和MybatisX&#xff0c;点击下载。 2.新建一个springboot模板&#xff0c;选择的依赖如下 3.…

初探Spring采用Spring配置文件管理Bean

文章目录Spring容器演示--采用Spring配置文件管理Bean&#xff08;一&#xff09;创建Maven项目&#xff08;二&#xff09;添加Spring依赖&#xff08;三&#xff09;创建杀龙任务类&#xff08;四&#xff09;创建勇敢骑士类&#xff08;五&#xff09;采用传统方式让勇敢骑士…