数据采集与融合技术-第二次实践作业

作业1

要求:在中国气象网(http://www.weather.com.cn)给定城市集的 7日天气预报,并保存在数据库

Gitee链接
https://gitee.com/xiaoaibit/102202131_LX/blob/master/homework2/demo1.py
from bs4 import BeautifulSoup
from bs4 import UnicodeDammit
import urllib.request
import sqlite3

# 定义一个处理数据库的类
class WeatherDB:
    def openDB(self):
        # 连接到SQLite数据库文件weathers.db,如果文件不存在则会自动创建
        self.con=sqlite3.connect("weathers.db")
        # 创建一个游标对象用于执行SQL命令
        self.cursor=self.con.cursor()
        try:
            # 尝试创建一个weathers表,如果表已存在则忽略
            self.cursor.execute("create table weathers (wCity varchar(16),wDate varchar(16),wWeather varchar(64),wTemp varchar(32),constraint pk_weather primary key (wCity,wDate))")
        except:
            # 如果表已存在,删除所有数据
            self.cursor.execute("delete from weathers")

    def closeDB(self):
        # 提交数据库事务,并关闭数据库连接
        self.con.commit()
        self.con.close()

    def insert(self, city, date, weather, temp):
        # 向weathers表插入一条天气记录
        try:
            self.cursor.execute("insert into weathers (wCity,wDate,wWeather,wTemp) values (?,?,?,?)",
                                (city, date, weather, temp))
        except Exception as err:
            # 如果插入失败,打印错误信息
            print(err)

    def show(self):
        # 查询并打印weathers表中的所有记录
        self.cursor.execute("select * from weathers")
        rows = self.cursor.fetchall()
        for row in rows:
            # 格式化打印每条记录
            print("%-16s%-16s%-32s%-16s%-16s" % (row[0], row[1], row[2], row[3], row[4]))

# 定义一个用于获取和处理天气数据的类
class WeatherForecast:
    def __init__(self):
        # 设置HTTP请求头,模拟浏览器访问
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/129.0.0.0 Safari/537.36 Edg/129.0.0.0"}
        # 定义城市代码映射
        self.cityCode = {"北京": "101010100", "上海": "101020100", "广州": "101280101", "深圳": "101280601"}

    def forecastCity(self, city):
        # 构造城市天气页面的URL
        url = "http://www.weather.com.cn/weather/" + self.cityCode[city] + ".shtml"
        try:
            # 创建HTTP请求对象
            req = urllib.request.Request(url, headers=self.headers)
            # 发送请求并获取响应数据
            data = urllib.request.urlopen(req)
            data = data.read()
            # 处理响应数据的编码
            dammit = UnicodeDammit(data, ["utf-8", "gbk"])
            data = dammit.unicode_markup
            # 使用BeautifulSoup解析HTML
            soup = BeautifulSoup(data, "lxml")
            # 选择包含天气信息的元素
            lis = soup.select("ul[class='t clearfix'] li")
            for li in lis:
                try:
                    # 提取日期、天气情况、温度等信息
                    date=li.select('h1')[0].text
                    weather=li.select('p[class="wea"]')[0].text
                    if not li.select('p[class="tem"] span'):
                        temp=li.select('p[class="tem"] i')[0].text
                    else :
                        temp = li.select('p[class="tem"] span')[0].text+"/"+li.select('p[class="tem"] i')[0].text
                    # 打印并存储提取的天气信息
                    print(city,date,weather,temp)
                    self.db.insert(city,date,weather,temp)
                except Exception as err:
                    # 如果提取信息失败,打印错误信息
                    print(err)
        except Exception as err:
             # 如果请求失败,打印错误信息
             print(err)

    def process(self, cities):
        # 初始化WeatherDB对象
        self.db = WeatherDB()
        self.db.openDB()
        # 遍历城市列表,获取每个城市的天气信息
        for city in cities:
            self.forecastCity(city)
        # 关闭数据库连接
        self.db.closeDB()

# 创建WeatherForecast对象
ws = WeatherForecast()
# 处理指定城市的天气信息
ws.process(["北京", "上海", "广州", "深圳"])
# 打印完成信息
print("completed")

结果

心得体会

在开发这个天气信息抓取和存储的小项目时,我学习到了几个重要的概念和技巧:

HTTP请求

通过urllib.request模块,我学会了如何发送HTTP请求来获取网页数据。设置合适的请求头来模拟浏览器行为,以便更好地与服务器进行交互。

HTML解析

使用BeautifulSoup库,我掌握了如何解析HTML文档。这让我能够从复杂的网页结构中提取出我想要的数据。

字符编码处理

通过UnicodeDammit类,我学会了如何处理不同编码的网页内容,确保数据能够正确地被解析和显示。

数据库操作

使用sqlite3模块,我了解了如何在Python中操作SQLite数据库,包括创建表、插入数据和查询数据。

作业2

要求: 用 requests 和 BeautifulSoup 库方法定向爬取股票相关信息,并存储在数据库中。

Gitee链接
https://gitee.com/xiaoaibit/102202131_LX/blob/master/homework2/demo2.py
import requests
import re
import pandas as pd
import sqlite3
# 初始化一个空列表,用于存储解析后的数据
data = []
# 定义API的URL
url = 'https://76.push2.eastmoney.com/api/qt/clist/get?cb=jQuery11240586371080087019_1728982019591&pn=1&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&dect=1&wbp2u=|0|0|0|web&fid=f3&fs=m:0+t:6,m:0+t:80,m:1+t:2,m:1+t:23,m:0+t:81+s:2048&fields=f1,f2,f3,f4,f5,f6,f7,f8,f9,f10,f12,f13,f14,f15,f16,f17,f18,f20,f21,f23,f24,f25,f22,f11,f62,f128,f136,f115,f152&_=1728982019595'
# 发送GET请求到API
res = requests.get(url)
# 设置响应的编码为utf-8,确保中文字符能够正确显示
res.encoding = 'utf-8'
# 初始化一个空列表,用于存储解析后的每一行数据
result = []
# 获取响应的文本内容
data = res.text
# 定义正则表达式模式,用于匹配不同的股票数据字段
id_pattern = r'"(f12)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
name_pattern = r'"(f14)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
newPrice_pattren = r'"(f2)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
price_change_amplitude_pattren = r'"(f3)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
price_change_Lines_pattren = r'"(f4)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
volume_pattren = r'"(f5)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
turnover_pattren = r'"(f6)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
amplitude_pattren = r'"(f7)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
highest_pattren = r'"(f15)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
lowest_pattren = r'"(f16)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
today_pattren = r'"(f17)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
yesteday_pattren = r'"(f18)":\s*(-?\d+(?:\.\d+)?|"[^"]*")'
# 使用正则表达式提取数据
id = re.findall(id_pattern, data)
name = re.findall(name_pattern, data)
newPrice = re.findall(newPrice_pattren, data)
price_change_amplitude = re.findall(price_change_amplitude_pattren, data)
price_change_Lines = re.findall(price_change_Lines_pattren, data)
volume = re.findall(volume_pattren, data)
turnover = re.findall(turnover_pattren, data)
amplitude = re.findall(amplitude_pattren, data)
highest = re.findall(highest_pattren, data)
lowest = re.findall(lowest_pattren, data)
today = re.findall(today_pattren, data)
yesteday = re.findall(yesteday_pattren, data)
# 遍历提取的数据,将其组织成字典格式,并添加到result列表中
for i in range(len(name)):
    result.append({
        '代码' : id[i][1],
        '名称': name[i][1],
        '最新价'	: newPrice[i][1],
        '涨跌幅' : price_change_amplitude[i][1],
        '涨跌额' : price_change_Lines[i][1],
        '成交量(手)'	: volume[i][1],
        '成交额'	: turnover[i][1],
        '振幅'	: amplitude[i][1],
        '最高'	: highest[i][1],
        '最低': lowest[i][1],
        '今开'	: today[i][1],
        '昨收'	: yesteday[i][1]
    })
# 将result列表转换为Pandas DataFrame
df = pd.DataFrame(result)
# 打印DataFrame
print(df)
# 定义数据库名称
db_name = 'stock_data.db'
# 连接到SQLite数据库
# 如果文件不存在,会自动在当前目录创建
conn = sqlite3.connect(db_name)
cursor = conn.cursor()
# 创建表
# 如果表已经存在,则忽略
cursor.execute('''
CREATE TABLE IF NOT EXISTS stock_info (
    code TEXT,
    name TEXT,
    new_price TEXT,
    price_change_amplitude TEXT,
    price_change_lines TEXT,
    volume TEXT,
    turnover TEXT,
    amplitude TEXT,
    highest TEXT,
    lowest TEXT,
    today TEXT,
    yesterday TEXT
)
''')
# 插入数据
for item in result:
    cursor.execute('''
    INSERT INTO stock_info (code, name, new_price, price_change_amplitude, price_change_lines, volume, turnover, amplitude, highest, lowest, today, yesterday)
    VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
    ''', (item['代码'], item['名称'], item['最新价'], item['涨跌幅'], item['涨跌额'], item['成交量(手)'], item['成交额'], item['振幅'], item['最高'], item['最低'], item['今开'], item['昨收']))
# 提交事务
conn.commit()
# 关闭连接
cursor.close()
conn.close()

结果

心得体会

自动化与效率

通过编写脚本来自动化数据获取和处理流程,可以显著提高工作效率。这不仅减少了重复性工作,还允许我们有更多的时间来分析数据和做出决策。

数据清洗的重要性

在数据分析之前,数据清洗是一个重要的步骤。它可以确保数据的质量和分析结果的准确性。不准确的数据会导致错误的结论,因此这一步骤不容忽视。

正则表达式的威力

正则表达式是一个非常强大的工具,它可以用来进行复杂的文本搜索、替换和提取。然而,它也需要仔细设计模式以避免错误。掌握正则表达式可以大大提升处理字符串数据的能力。

数据库操作的重要性

学习如何与数据库交互是处理数据的关键技能。它允许我们存储、查询和分析大量数据。了解SQL语言和数据库设计原则是必不可少的。

作业3

要求: 爬取中国大学 2021 主榜(https://www.shanghairanking.cn/rankings/bcur/2021)所有院校信息,并存储在数据库中,同时将浏览器 F12 调试分析的过程录制 Gif 加入至博客中。

Gitee链接
https://gitee.com/xiaoaibit/102202131_LX/blob/master/homework2/demo3.py
import re
import requests
from bs4 import BeautifulSoup, UnicodeDammit
import pandas as pd
import sqlite3

# 定义一个类,用于管理与SQLite数据库的交互
class schoolDB:
    def openDB(self):
        # 连接到SQLite数据库,并设置文本工厂为字符串,以避免将字符串转换为数字
        self.con = sqlite3.connect("school.db")
        self.con.text_factory = str
        self.cursor = self.con.cursor()
        try:
            # 创建一个新表,如果表已存在则忽略
            self.cursor.execute('create table schoolInfo (rank int, univNameCn varchar(10), province varchar(10),univCategory varchar(10),score decimal)')
        except Exception as err:
            # 如果创建表时出现错误,打印错误信息
            print(err)

    def closeDB(self):
        # 提交事务并关闭数据库连接
        self.con.commit()
        self.con.close()

    def insertDB(self, rank, univNameCn, province, univCategory, score):
        try:
            # 向数据库插入一条新记录
            self.cursor.execute('insert into schoolInfo values(?,?,?,?,?)', (rank, univNameCn, province, univCategory, score))
        except Exception as err:
            # 如果插入数据时出现错误,打印错误信息
            print(err)

    def showDB(self):
        # 查询并打印数据库中的所有记录
        self.cursor.execute('select * from schoolInfo')
        rows = self.cursor.fetchall()
        print(rows)
        for row in rows:
            print('%-32d%-32s%-32s%-32s%-32f' % (row[0], row[1], row[2], row[3], row[4]))

# 定义一个列表,用于存储省份和学校类型的映射关系
table = ['', 'false', 'null', 0, "理工", "综合", 'true', "师范", "双一流", "211", "江苏", "985", "农业", "山东", "河南", "河北", "北京", "辽宁", "陕西", "四川", "广东", "湖北", "湖南", "浙江", "安徽", "江西", "黑龙江", "吉林", "上海", "福建", "山西", "云南", "广西", 2, "贵州", "甘肃", "内蒙古", "重庆", "天津", "新疆"]
results = []

# 定义要请求的URL
url = "https://www.shanghairanking.cn/_nuxt/static/1728872418/rankings/bcur/2021/payload.js"
res = requests.get(url)
data = res.text
dammit = UnicodeDammit(data,['utf-8'])
data = dammit.unicode_markup

# 定义正则表达式模式,用于匹配不同的数据字段
univNameCn_pattern = 'univNameCn:\s*"([\u4e00-\u9fa5]+)"'
province_pattern = 'province:\s*([a-z])'
univCategory_pattern = 'univCategory:\s*([a-z])'
score_pattern = 'score:\s*([0-9]+(?:\.[0-9]+)?|[a-zA-Z]+)'

# 使用正则表达式提取数据
univNameCn = re.findall(univNameCn_pattern, data)
province = re.findall(province_pattern, data)
univCategory = re.findall(univCategory_pattern, data)
score = re.findall(score_pattern, data)

# 创建数据库实例并打开数据库
myDb = schoolDB()
myDb.openDB()

# 遍历提取的数据,将其组织成字典格式,并添加到results列表中
for i in range(50):
    rank = i + 1
    n = univNameCn[i]
    p = table[ord(province[i]) - 97]
    c = table[ord(univCategory[i]) - 97]
    s = score[i]
    myDb.insertDB(rank, n, p, c, s)
    results.append({
        '排名': rank,
        '学校名称': n,
        '省市': p,
        '学校类型': c,
        '总分': s
    })

# 将results列表转换为Pandas DataFrame
df = pd.DataFrame(results)
print(df)

# 显示数据库中的所有记录
myDb.showDB()

# 关闭数据库连接
myDb.closeDB()

结果

心得体会

理解数据源的重要性

在开始编码之前,深入理解数据源的结构和内容至关重要。这有助于我们选择合适的方法来提取和解析数据。在本项目中,通过分析js代码结构,我们使用正则表达式成功提取了所需数据,这体现了对数据源深入理解的重要性。

posted @ 2024-10-16 02:03  PZn  阅读(20)  评论(0编辑  收藏  举报