資料採集與融合技術作業2

xhbyq發表於2024-10-19

作業①

1)在中國氣象網(http://www.weather.com.cn)給定深圳的7日天氣預報,並儲存在資料庫。

a、主要程式碼展示和分析

這個類負責從指定的 URL 抓取天氣預報資料並將其插入到資料庫中
class WeatherForecast:
    def __init__(self):
        self.headers = {
            "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={"深圳":"101280601"}
  • init: 初始化HTTP請求頭(模擬瀏覽器行為),並定義一個城市程式碼字典,將城市名稱對映到其相應的天氣程式碼(此處僅包含深圳)。
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,"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
                    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)
  • forecastCity: 獲取指定城市的天氣資料:
  • 檢查城市是否在程式碼字典中。
  • 構建天氣網站的URL併發起請求。
  • 使用UnicodeDammit處理返回的資料,確保其正確解碼。
  • 使用BeautifulSoup解析HTML,提取天氣資訊(日期、天氣狀況、溫度)。
  • 將提取到的天氣資料插入到資料庫中。
  • 在過程中捕獲可能發生的異常並列印錯誤資訊。
這個類負責建立,資料等資料庫運算元據庫
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))")
        except:
            self.cursor.execute("delete from weathers")
    def closeDB(self):
        self.con.commit()
        self.con.close()
  • openDB: 連線到SQLite資料庫,如果表不存在則建立一個名為weathers的表。如果表已存在,則清空表中的資料(delete from weathers)。
  • closeDB: 提交資料庫事務並關閉連線。
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()
        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]))
  • insert: 向weathers表中插入一條新的天氣記錄。如果插入失敗,捕獲異常並列印錯誤資訊。
  • show: 從weathers表中選擇所有記錄並格式化輸出。

b、輸出資訊

c、Gitee資料夾連結

2)心得體會

  • 程式碼結構: 程式碼邏輯清晰,將資料庫操作和資料抓取分開,使得程式碼易於維護。物件導向的設計使得每個類的職責明確。
  • 異常處理: 透過 try...except 塊處理異常,增強了程式的健壯性,避免因某個步驟失敗導致整個程式崩潰。

作業②

1)用requests和BeautifulSoup庫方法定向爬取東方財富網:(https://www.eastmoney.com/)股票相關資訊,並儲存在資料庫中

a、主要程式碼展示和分析

這個類負責從指定的 URL 抓取股票資料並將其插入到資料庫中。
class StockGet:
    def __init__(self):
        self.loginheaders = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.164 Safari/537.36',
}

    def GetStock(self):
        url="http://6.push2.eastmoney.com/api/qt/clist/get?cb=jQuery112408105779319969169_1634089326282&pn=1&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&fid=f3&fs=m:0+t:6,m:0+t:80,m:1+t:2,m:1+t:23&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&_=1634089326289"
        data = getHTMLText(url, self.loginheaders)
        td1 = re.findall(r'"f14":(.*?),', data)
        # 程式碼
        td2 = re.findall(r'"f12":(.*?),', data)
        # 最新報價
        td3 = re.findall(r'"f2":(.*?),', data)
  • init 方法:定義請求頭以模擬瀏覽器訪問,提高請求的成功率。
  • GetStock 方法:透過 getHTMLText 函式獲取資料,使用正規表示式提取所需的股票資訊(如名稱、程式碼、價格等)。
  • 資料抓取函式 getHTMLText,使用 requests 庫傳送 GET 請求,獲取網頁內容。透過設定超時和編碼來確保請求的可靠性。
    將提取到的資料插入到 stockDB 的資料庫中,並呼叫 show 方法顯示結果。
這個類負責資料庫的連線和操作,包括開啟、關閉資料庫,插入資料,以及展示資料庫中的內容
class stockDB:
    # 開啟資料庫的方法
    def openDB(self):
        self.con = sqlite3.connect("stock.db")
        self.cursor = self.con.cursor()
        try:
            self.cursor.execute(
                "create table equity (sID varchar(16),sName varchar(64),sPrice varchar(16),sRFExtent varchar(16),sRFQuota varchar(16),sNum varchar(16),sQuota varchar(16),sExtent varchar(16),sHigh varchar(16),sLow varchar(16),sToday varchar(16),sYesterday varchar(16),constraint pk_stock primary key (sID,sName))")
        except:
            self.cursor.execute("delete from equity")

    # 關閉資料庫的方法
    def closeDB(self):
        self.con.commit()
        self.con.close()

    # 插入資料的方法
    def insert(self, ID, name, price, RFextent, RFquota, num, quota, extent, high, low, today, yesterday):
        try:
            self.cursor.execute(
                "insert into equity (sID,sName,sPrice,sRFExtent,sRFQuota,sNum,sQuota,sExtent,sHigh,sLow,sToday,sYesterday) values (?,?,?,?,?,?,?,?,?,?,?,?)",
                (ID, name, price, RFextent, RFquota, num, quota, extent, high, low, today, yesterday))
        except Exception as err:
            print(err)

    # 列印資料庫內容的方法
    def show(self):
        self.cursor.execute("select * from equity")
        rows = self.cursor.fetchall()
        print(
            "{:^10}\t{:^8}\t{:^10}\t{:^20}\t{:^10}\t{:^10}\t{:^10}\t{:^10}\t{:^10}\t{:^10}\t{:^10}\t{:^10}\t{:^10}\t".format(
                "序號", "程式碼", "名稱", "最新價(元)", "漲跌幅(%)", "跌漲額(元)", "成交量", "成交額(元)", "振幅(%)", "最高", "最低", "今開", "昨收"))
        i = 1
        for row in rows:
            print("{:^10}\t{:^8}\t{:^10}\t{:^20}\t{:^10}\t{:^18}\t{:^16}\t{:^10}\t{:^10}\t{:^10}\t{:^10}\t{:^10}\t{:^10}\t".format(i, row[0],row[1],row[2],row[3],row[4],row[5],row[6],row[7],row[8],row[9],row[10],row[11],))
            i += 1
  • openDB 方法:嘗試連線 SQLite 資料庫並建立一個名為 equity 的表。如果表已經存在,則刪除其中的所有記錄;使用 try...except 塊來處理表建立的異常,這樣在表已存在的情況下不會中斷程式。
  • closeDB 方法:
    提交任何未儲存的更改並關閉資料庫連線。
  • insert 方法:插入一條股票記錄。使用 try...except 塊捕捉可能的異常,確保程式碼的健壯性。
  • show 方法:從資料庫中查詢所有記錄並列印。格式化輸出使得結果在控制檯上看起來整齊。

b、輸出資訊

c、Gitee資料夾連結

2)心得體會

  • 正規表示式在資料提取方面非常有效,但過度使用可能會導致程式碼可讀性降低。可以考慮使用 JSON 解析庫(如 json 模組)直接處理 API 返回的資料,這樣可以簡化程式碼並提高可讀性。
  • 資料庫表的設計較為簡單,適用於小型專案。對於大規模資料,可能需要考慮更復雜的表設計和索引策略。

作業③

1)爬取中國大學 2020主榜所有院校資訊,並儲存在資料庫中

a、主要程式碼展示和分析

該函式從獲取的JSON資料中提取前 num 名大學的資訊,並將這些資訊儲存到 ulist 列表中,同時格式化輸出這些大學的排名資訊
def printUnivList(ulist, html, num):
    '''提取 html 網頁內容中 前 num 名大學資訊到 ulist列表中 '''   
    data = json.loads(html)  # 對資料進行解碼    
    # 提取 資料 rankings 包含的內容
    content = data['data']['rankings']    
    
    # 把 學校的相關資訊放到  ulist 裡面
    for i in range(num):
        index = content[i]['rankOverall']
        name  = content[i]['univNameCn']
        score = content[i]['score']
        category  = content[i]['univCategory']
        province = content[i]['province']  # 提取省份資訊
        ulist.append([index, name, score, category, province])        

    # 列印前 num 名的大學      
    tplt = "{0:^10}\t{1:^10}\t{2:^10}\t{3:^10}\t{4:^10}"  # 更新格式,而不使用{3}
    print(tplt.format("排名 ", "學校名稱", "總分", "型別", "省份"))  # 更新這裡,保持一致
    for i in range(num):
        u = ulist[i]        
        print(tplt.format(u[0], u[1], u[2], u[3], u[4]))  # 直接傳入值
  • 使用了 json.loads 對網頁的返回內容進行JSON解碼,這意味著該網頁返回的資料是一個JSON格式的結構。
  • 從 data['data']['rankings'] 提取大學的具體排名資訊,包含排名、學校名稱、得分、類別(如綜合類、理工類等)以及所在省份。
  • 使用 tplt 定義了表格的輸出格式,確保列印的大學資訊整齊對齊。使用了 center(^) 方式格式化輸出。
該函式 將提取到的大學資訊儲存到SQLite資料庫中
def save_to_db(ulist):
    '''將大學資訊儲存到SQLite資料庫'''
    conn = sqlite3.connect('school.db')
    cursor = conn.cursor()
    
    # 建立表
    cursor.execute('''
        CREATE TABLE IF NOT EXISTS university_rankings (
            rank INTEGER,
            name TEXT,
            score REAL,
            category TEXT,
            province TEXT  -- 新增省份列
        )
    ''')
    
    # 插入資料
    cursor.executemany('''
        INSERT INTO university_rankings (rank, name, score, category, province)
        VALUES (?, ?, ?, ?, ?)
    ''', ulist)

    conn.commit()  # 提交事務
    conn.close()   # 關閉連線
  • 首先使用 sqlite3.connect() 連線到本地的 school.db 資料庫檔案,如果該檔案不存在,會自動建立。
  • 使用 CREATE TABLE IF NOT EXISTS 建立一個名為 university_rankings 的表,這個表包含了排名、學校名稱、得分、類別和省份資訊。
  • executemany() 方法批次插入大學資訊, ? 佔位符用於防止SQL隱碼攻擊風險。
  • 在插入資料後,呼叫 commit() 提交事務,然後關閉資料庫連線。

b、輸出資訊

c、瀏覽器 F12 除錯分析的過程

d、Gitee資料夾連結

2)心得體會

  • 使用SQLite資料庫儲存資料是一種輕量級的選擇,適用於小型專案。這種方式無需安裝複雜的資料庫系統,適合初學者學習資料庫操作。
  • 整個程式按照功能劃分為多個函式,每個函式都執行一個特定的任務:獲取網頁、提取資料、列印資料、儲存資料。這樣的設計使得程式碼易於維護和擴充套件。

相關文章