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

发布时间 2023-10-17 01:02:58作者: muyiyYANG

2023数据采集与融合技术实践作业二

作业①:

  • 要求:

    • 在中国气象网(http://www.weather.com.cn)给定城市集的7日天气预报,并保存在数据库。
    • 输出信息:
    序号 地区 日期 天气信息 温度
    1 北京 8日(今天) 小雨转晴 ...
  • Gitee文件夹链接

代码:

from bs4 import BeautifulSoup
from bs4 import UnicodeDammit
import urllib.request
import sqlite3

class WeatherDB:
    # 打开数据库
    def openDB(self):
        self.con=sqlite3.connect("weathers.db")# 存储天气预报数据
        self.cursor=self.con.cursor()
        try:
            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))")# cursor.execute()执行sql语句
        except:
            self.cursor.execute("delete from weathers")
    # 关闭数据库
    def closeDB(self):
        self.con.commit()
        self.con.close()
    # 插入数据
    def insert(self, city, date, weather, temp):
        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):
        self.cursor.execute("select * from weathers")
        rows = self.cursor.fetchall()# fetchall()返回多个元组,即返回多个记录(rows),如果没有结果 则返回 ()
        print("%-16s%-16s%-32s%-16s" % ("city", "date", "weather", "temp"))# 格式化输出
        for row in rows:
            print("%-16s%-16s%-32s%-16s" % (row[0], row[1], row[2], row[3]))

class WeatherForecast:
    def __init__(self):
        self.headers = {
            # Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36
            "User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9pre) Gecko/2008072421 Minefield/3.0.2pre"}
        # 存放城市和对应编码的字典
        self.cityCode = {"北京": "101010100", "上海": "101020100", "广州": "101280101", "深圳": "101280601"}

    def forecastCity(self, city):
        if city not in self.cityCode.keys():
            print(city + " code cannot be found")
            return
        url = "http://www.weather.com.cn/weather/" + self.cityCode[city] + ".shtml"
        try:
            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
            soup = BeautifulSoup(data, "html.parser")
            lis = soup.select("ul[class='t clearfix'] li")# 查找属性值为t clearfix的ul标签下的所有li标签
            for li in lis:
                try:
                    date = li.select('h1')[0].text# 日期
                    weather = li.select('p[class="wea"]')[0].text# 天气状态
                    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):
        self.db = WeatherDB()
        self.db.openDB()
        # 遍历城市
        for city in cities:
            self.forecastCity(city)
        # self.db.show()
        self.db.closeDB()

ws = WeatherForecast()#实例化天气预报对象
ws.process(["北京", "上海", "广州", "深圳"])
print("completed")

图片:

心得体会:

代码首先定义了一个WeatherDB类,用于操作数据库。
openDB方法用于打开数据库连接并创建表格,如果表格已存在则删除原有数据。
insert方法用于插入一条记录到数据库中。
show方法用于查询并展示数据库中的所有记录。
closeDB方法用于提交事务并关闭数据库连接。
接着定义了WeatherForecast类,该类包含了一个城市代码与城市名称的映射字典cityCode,以及一个获取天气预报的方法forecastCity。
forecastCity方法根据给定的城市名称在网站上获取对应城市的天气预报数据,并解析数据保存到数据库中。
最后实例化WeatherForecast对象,并调用process方法传入需要获取天气预报的城市列表,即可开始爬取和存储天气预报数据。

作业②

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

  • 候选网站:东方财富网:https://www.eastmoney.com/
    新浪股票:http://finance.sina.com.cn/stock/

  • 技巧:在谷歌浏览器中进入F12调试模式进行抓包,查找股票列表加载使用的url,并分析api返回的值,并根据所要求的参数可适当更改api的请求参数。根据URL可观察请求的参数f1、f2可获取不同的数值,根据情况可删减请求的参数。

  • 参考链接:https://zhuanlan.zhihu.com/p/50099084

  • 输出信息:

代码:

import json
import requests
import sqlite3

def getHtml():
    url = "http://38.push2.eastmoney.com/api/qt/clist/get?cb=jQuery112407987064832629414_1696658970374&pn=1&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&wbp2u=%7C0%7C0%7C0%7Cweb&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&_=1696658970375"
    response = requests.get(url)

    try:
        # 从响应内容中提取有效的 JSON 部分
        jsonp = response.text
        json_data = jsonp[jsonp.index('(') + 1: jsonp.rindex(')')]

        # 解析为 Python 对象
        data = json.loads(json_data)
        return data
    except (json.JSONDecodeError, ValueError) as e:
        print("JSON解析错误:", str(e))
        print("实际响应内容:", response.text)
        return None

def saveToDatabase(data):
    conn = sqlite3.connect('股票.db')

    # 创建表格(如果不存在)
    create_table_query = '''
    CREATE TABLE IF NOT EXISTS stock_data (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        code VARCHAR(10),
        name VARCHAR(255),
        price DECIMAL(10, 2),
        change_percent DECIMAL(10, 2),
        change_amount DECIMAL(10, 2),
        volume BIGINT,
        turnover DECIMAL(18, 2),
        increase_percent DECIMAL(10, 2)
    )
    '''
    conn.execute(create_table_query)

    # 插入数据
    for item in data["data"]["diff"]:
        code = item["f12"]
        name = item["f14"]
        price = float(item["f2"])
        change_percent = float(item["f3"])
        change_amount = float(item["f4"])
        volume = int(item["f5"])
        turnover = float(item["f6"])
        increase_percent = float(item["f7"])

        insert_query = '''
        INSERT INTO stock_data (code, name, price, change_percent, change_amount, volume, turnover, increase_percent)
        VALUES (?, ?, ?, ?, ?, ?, ?, ?)
        '''
        conn.execute(insert_query, (code, name, price, change_percent, change_amount, volume, turnover, increase_percent))

    # 提交更改并关闭连接
    conn.commit()
    conn.close()

    print("数据已保存到数据库文件。")


def fetchDataFromDatabase():
    conn = sqlite3.connect('股票.db')
    cursor = conn.cursor()

    # 查询数据
    select_query = "SELECT * FROM stock_data"
    cursor.execute(select_query)

    # 获取结果并打印
    results = cursor.fetchall()
    for row in results:
        id, code, name, price, change_percent, change_amount, volume, turnover, increase_percent = row
        print(f"{id}\t{code}\t{name}\t{price}\t{change_percent}\t{change_amount}\t{volume}\t{turnover}\t{increase_percent}")

    # 关闭连接
    conn.close()


if __name__ == '__main__':
    data = getHtml()
    if data:
        saveToDatabase(data)
        fetchDataFromDatabase()

图片:

心得体会:

从响应内容提取有效的JSON部分:在获取网页响应后,需要从响应内容中提取有效的JSON部分进行解析。这里使用了字符串的索引和切片操作来提取JSON部分。
JSON解析错误处理:在将响应内容解析为Python对象时,可能会发生JSON解析错误。需要对解析过程进行异常处理,并打印出实际响应内容以便调试。
SQLite数据库操作:代码中使用了SQLite数据库进行数据存储。需要注意创建表格的SQL语句和插入数据的SQL语句的正确性,以及正确提交更改和关闭连接。
数据的提取与赋值:在将JSON数据插入到数据库中时,需要根据数据的结构进行正确的提取和赋值操作,确保插入的数据类型与表格定义的类型一致。

作业③:

代码:

import re
import requests
import pandas as pd
import pymysql


def get_universities_ranking():
    # 创建省份和大学类别的字母映射字典
    province_mapping = {
        'k': '江苏', 'n': '山东', 'o': '河南', 'p': '河北', 'q': '北京', 'r': '辽宁', 's': '陕西', 't': '四川', 'u': '广东',
        'v': '湖北', 'w': '湖南', 'x': '浙江', 'y': '安徽', 'z': '江西', 'A': '黑龙江', 'B': '吉林', 'C': '上海', 'D': '福建',
        'E': '山西', 'F': '云南', 'G': '广西', 'I': '贵州', 'J': '甘肃', 'K': '内蒙古', 'L': '重庆', 'M': '天津', 'N': '新疆',
        'Y': '海南'
    }

    univ_category_mapping = {
        'f': '综合', 'e': '理工', 'h': '师范', 'm': '农业', 'T': '林业',
    }

    url = 'https://www.shanghairanking.cn/_nuxt/static/1697106492/rankings/bcur/2021/payload.js'
    header = {"User-Agent": "Mozilla/5.0 (Windows; U; Windows NT 6.0 x64; en-US; rv:1.9pre) Gecko/2008072421 Minefield/3.0.2pre"}
    resp = requests.get(url, headers=header)
    resp.raise_for_status()
    resp.encoding = resp.apparent_encoding

    # 正则表达式匹配内容
    pattern = re.compile(r'univNameCn:"(?P<univNameCn>.*?)",.*?'     # 匹配学校名称
                         r'univCategory:(?P<univCategory>.*?),.*?'  # 匹配大学类型
                         r'province:(?P<province>.*?),'          # 匹配省份
                         r'score:(?P<score>.*?),'                # 匹配总分
                         , re.S)                                 # 让点也可以匹配换行符

    # 查找所有结果
    results = pattern.findall(resp.text)

    # 遍历结果,并进行映射转换
    for idx, result in enumerate(results):
        univNameCn, univCategory, province, score = result
        mapped_province = province_mapping.get(province, province)               # 如果找不到映射,则使用原始值
        mapped_category = univ_category_mapping.get(univCategory, univCategory)  # 如果找不到映射,则使用原始值
        results[idx] = (idx + 1, univNameCn, mapped_province, mapped_category, score)

    # 使用pandas创建DataFrame
    df = pd.DataFrame(results, columns=['排名', '学校', '省市', '类型', '总分'])

    return df


# 获取大学排名数据
df = get_universities_ranking()

# 将DataFrame保存到MySQL数据库
def save_to_mysql(df):
    # 连接到数据库
    conn = pymysql.connect(host='localhost',
                           port=3307,
                           user='root',
                           password='123456',
                           db='Data acquisition')

    # 创建表
    create_table_sql = '''
        CREATE TABLE IF NOT EXISTS universities_ranking (
            排名 INT,
            学校 VARCHAR(255),
            省市 VARCHAR(255),
            类型 VARCHAR(255),
            总分 VARCHAR(255)
        )
    '''

    with conn.cursor() as cursor:
        cursor.execute(create_table_sql)
        conn.commit()

    # 将数据插入表中
    insert_data_sql = '''
        INSERT INTO universities_ranking (排名, 学校, 省市, 类型, 总分) VALUES (%s, %s, %s, %s, %s)
    '''
    with conn.cursor() as cursor:
        for row in df.itertuples(index=False):
            cursor.execute(insert_data_sql, row)
        conn.commit()

    # 关闭数据库连接
    conn.close()

# 调用保存函数
save_to_mysql(df)

抓包过程:

图片:

心得体会:

使用requests库发送HTTP请求,获取大学排名数据的网页内容。
使用正则表达式匹配网页内容,提取学校名称、大学类型、省市、总分等信息。
根据预定义的字典,将大学类型和省市进行映射转换。
使用pandas库创建DataFrame,并将提取到的信息存储到DataFrame中。
定义函数save_to_mysql,连接到MySQL数据库,并创建表(universities_ranking)。
使用pandas的itertuples方法遍历DataFrame中的每一行数据,并执行插入操作,将数据存储到MySQL数据库中。
调用save_to_mysql函数,将DataFrame中的数据保存到MySQL数据库中。