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

发布时间 2023-10-09 16:45:35作者: 陈子阳

代码放在码云:https://gitee.com/yangzizizi/crawl_projec.git

第二次作业

  • 作业1:

    要求:在中国气象网给定城市集的7日天气预报,并保存在数据库。

作业一代码文件夹:作业一

代码显示如下

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))")
        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()
        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 = {
            "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,"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)

    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")

保存在数据库,本文采用Navicat进行数据库可视化

  • 心得体会

    对于本次实验,学习到的是如何利用bs4库将数据从网站中爬取后,利用sqlite3的数据库将数据持久化。

    这次实验是复现书本上的例题,让我对bs4库有了清晰的认识,也懂得如何使用bs库和数据存储。

  • 作业2:

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

作业二代码文件夹:作业二

代码显示如下

import requests
import json
from fake_useragent import UserAgent
import pandas as pd
from sqlalchemy import create_engine
import mysql.connector

def web_page(n):
    url = f"http://16.push2.eastmoney.com/api/qt/clist/get?cb=jQuery112408936794087215907_1696658940293&pn={n}&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&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&_=1696658940294"
    urll = 'https://98.push2.eastmoney.com/api/qt/clist/get?cb=jQuery1124029546986442297585_1696746433261&pn=1&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&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&_=1696746433262'
    headers = {
        'User-Agent':UserAgent().chrome
    }
    '''
    序号,股票代码:f12,股票名称:f14,最新报价:f2,涨跌幅:f3,涨跌额:f4,成交量:f5,成交额:f6
    振幅:f7,最高:f15,最低:f16,今开:f17,昨收:f18
    f12,f14,f2,f3,f4,f5,f6,f7,f15,f16,f17,f18
    '''
    res = requests.get(url=url,headers=headers)
    res.encoding = res.apparent_encoding
    # print(type(res.text),res.text)

    # 提取括号内的JSON数据部分
    start_index = res.text.find('(') + 1
    end_index = res.text.rfind(')')
    json_data = res.text[start_index:end_index]
    # 解析JSON数据
    # print(json_data)
    # print(type(json_data))
    json_obj = json.loads(json_data)
    # 打印输出
    # print(type(json_obj))
    # print(json_obj)
    #取出data中的数据列表list
    data = json_obj['data']['diff']
    # print(data,type(data))
    global goods_list
    name = ['f12','f14','f2','f3','f4','f5','f6','f7','f15','f16','f17','f18']
    global count
    for li in data:
        list =[]
        list.append(count)
        for n in name:
            list.append(li[n])
        count += 1
        goods_list.append(list)
    # print(goods_list)
    # print(len(goods_list))

# def get_disdinct():
#     url = "https://quote.eastmoney.com/center/api/sidemenu.json"
#     headers = {
#         'User-Agent':UserAgent().chrome
#     }
#     res = requests.get(url=url,headers=headers)
#     res.encoding = res.apparent_encoding
#     json_data = json.loads(res.text)
#     # print(json_data)
#     # print(type(json_data))
#     # print(len(json_data))
#     for msg in json_data:
#         print(msg)


if __name__ == "__main__":
    n = int(input("请输入需要下载几页股票信息?"))
    goods_list = []
    count = 1
    for i in range(n):
        web_page(i+1)
    df = pd.DataFrame(data=goods_list,columns=['序号','股票代码','股票名称','最新报价','涨跌幅','涨跌额','成交量','成交额','振幅','最高','最低','今开','昨收'])
    df.set_index('序号')
    # print(df)
    engine = create_engine("mysql+mysqlconnector://root:123456@127.0.0.1:3306/homework1")
    df.to_sql("stock",engine,if_exists="replace",index=False)

保存在mysql数据库,本文采用Navicat进行数据库可视化

  • 心得体会

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

下图是F12进行抓包的过程,在开发者工具中,查找页面元素,寻找页面数据是从哪个网页中传递过来的。

寻找到该数据传递的网页之后,查看页面数据,发现是json数据的格式

于是学习了如何访问数据后,将其json格式的数据转化为python的字典,json.loads函数就起到了这个作用,同时要保证loads()函数中传递的参数需要是json格式数据,但是这个网页中并不是完整的json格式,所以参考代码中的字符串find函数,将不需要的部分,即不是json格式的部分去除,只需要自己想要的json数据即可。

本次作业需要将数据存储进数据库,本文采用了pandas中的to_sql。但是使用这个函数需要同时下载sqlalchemy库,和mysql-connector-python库

# 分别复制下列的代码进终端运行即可下载
pip install sqlalchemy
pip install mysql-connector-python

作业二让我学会了如何将下载的数据连接数据库,并将数据传入数据库

  • 作业3:

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

作业三代码文件夹:作业三

代码显示如下:

import requests
from fake_useragent import UserAgent
import re
import pandas as pd
from sqlalchemy import create_engine
import mysql.connector
url = 'https://www.shanghairanking.cn/_nuxt/static/1695811954/rankings/bcur/2021/payload.js'

headers = {
    'User-Agent':UserAgent().chrome
}
res = requests.get(url=url,headers=headers)
res.encoding = res.apparent_encoding
# print(type(res.text))
# print(res.text)

start_index = res.text.find("o")+3
end_index = res.text.find(")")
function_list_key= res.text[start_index:end_index].split(',')
# print(function_list)

start_index_1 = res.text.rfind("}")+1
end_index_1 = res.text.rfind(")")-2
function_list_value = res.text[start_index_1:end_index_1].split(",")
# print(function_list_value)
mapper = dict(zip(function_list_key,function_list_value))
# print(mapper)

name = re.findall(r'univNameCn:"(.*?)",',res.text)
# print(len(name))
score = re.findall(r',score:(.*?),',res.text)
# print(len(score))
# print(score)
# print(name)

province_new = []
province = re.findall(r'province:(.*?),',res.text)
# print(len(province),province)
for item in province:
    province_new.append(mapper[item])
# print(province_new,len(province_new))

category_new = []
category = re.findall(r'univCategory:(.*?),',res.text)
# print(len(category),category)
for item in category:
    category_new.append(mapper[item])
# print(category_new,len(category_new))


df = pd.DataFrame(columns=['排名','学校','省市','类型','总分'])
num = [i+1 for i in range(582)]
nnum = pd.Series(num)
sname = pd.Series(name)
sscore = pd.Series(score)
df['排名']= nnum
df['学校']=sname
df['总分']=sscore
df['省市']= province_new
df['类型']= category_new
# df.to_excel("123.xlsx")
engine = create_engine("mysql+mysqlconnector://root:123456@127.0.0.1:3306/homework1")
df.to_sql('school',engine,if_exists='replace',index=False)

保存在mysql数据库,本文采用Navicat进行数据库可视化

  • 心得体会

对于本次这个网站,采用抓包的方式进行寻找页面中传递的数据,具体过程在如下gif图像

对于本次实验,有一个疑难点,刚开始认为该网页为json数据格式,故与第二题一样,利用json.loads进行转化,但是发现报错,查找报错后发现,网站不是json数据,对于每个key并不是字符串。

于是对数据进行re正则提取,最终提取成功。实验得出,提取数据时,要认真判断数据的具体格式,再采用相对应的合适的方法进行提取。

同时学校的省市和类型,需要查看数据格式,发现以第一页的function与category与province一一对应,再采用正则表达式进行提取后,转化为字典即可,具体方式查看上述代码。