数据采集与融合第二次作业

作业一:

思路

(1)通过城市代码切换url,获取html

(2)7天的天气预报元素中,每天是一个li元素,7天的li结构是一样的,可以通过BeautifulSoup的元素查找方法来获取各个元素的值

(3)保存到数据库中

代码

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()
        i=1
        print("{:4}\t{:10}\t{:14}\t{:24}\t{:16}".format("序号","城市", "日期", "天气信息", "温度"))
        for row in rows:
            print("{:4}\t{:10}\t{:10}\t{:24}\t{:16}".format(i,row[0], row[1], row[2], row[3]))
            i+=1
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") #找到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 #温度
                    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")

运行结果

心得体会

(1)了解了sqlite3的数据库存储

(2)加强了CSS语法的运用

作业二:

思路

(1)过滤js文件,提取url

(2)对沪深A股、上证A股等不同板块的url切换

通过对比发现,只有两处不同,所以建立了两个字典用来切换

(3)翻页,以及自动停止

①爬取到最后一页:

文本中的total字段为总数据,东方财富网一页为20条数据,可以通过(总数据/20)向上取整来获得总页数,从而自动爬取到最后一页。

②翻页:通过对比,翻页是通过修改pn值来实现的。

(4)正则表达式匹配,对得到的text的处理


不同股票之间可以用 ' },{ '来进行切分,不同信息之间再用逗号切分,之后再通过冒号分隔来得到信息值。

(5)通过dataframe来结构化数据,存为xls文件

这一步包括

  • 提取所要的数据

  • 重命名列

  • 切换列的顺序

  • 新建路径

  • 保存文件等。

代码

import requests
import re
import pandas as pd
import math
import os
#用get方法访问服务器并提取页面数据
def getHtml(fs,page,k):
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3141.8 Safari/537.36}"
    }
    #页数是通过修改pn值,不同股票的url有两个地方不同,通过之后的字典fs和k来实现。
    url = "http://35.push2.eastmoney.com/api/qt/clist/get?cb=jQuery112402976183355999211_1601533720950&pn="+str(page)+"&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&fid=f3&fs="+fs+"&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&_="+k
    r = requests.get(url,headers=headers)
    pat = "\"data\":.*\]"
    data = re.compile(pat, re.S).findall(r.text) #正则表达式匹配
    #获取数据总条数,用于主函数中计算总页数,每页有20条数据,相除向上取整为总页数。
    t=re.findall(r"\"total\":[\d]*",data[0])
    to=t[0].split(':')
    total=eval(to[1])
    # 去除前面的total和diff数据
    data[0]=data[0][29:]
    return data,total
#获取单个页面股票数据
def getOnePageStock(fs,page,k):
    data = getHtml(fs,page,k)
    data=data[0]
    datas = data[0].split('},{') #不同股票分割
    stocks = []
    for i in range(len(datas)):
        stock = datas[i].replace('"',"").split(',') #不同信息分割,并且去掉引号
        for j in range(len(stock)):
            #冒号分割,获取信息的值
            t=stock[j].split(':')
            stock[j]=t[1]
        stocks.append(stock)
    return stocks
def main():
    #根据对不同url的分析,建立以下两个字典
    fs = {
        "沪深A股":"m:0+t:6,m:0+t:13,m:0+t:80,m:1+t:2,m:1+t:23",
        "上证A股":"m:1+t:2,m:1+t:23",
        "深证A股":"m:0+t:6,m:0+t:13,m:0+t:80",
        "新股":"m:0+f:8,m:1+f:8",
        "中小板":"m:0+t:13",
        "创业板":"m:0+t:80"
    }
    k = {
        "沪深A股": "1601536578738",
        "上证A股": "1601536578736",
        "深证A股": "1601536578759",
        "新股": "1601536578765",
        "中小板": "1601536578882",
        "创业板": "1601536578888"
    }
    dirs="东方财富网股票数据031804112/"
    #如果不存在,新建路径
    if not os.path.exists(dirs):
        os.makedirs(dirs)
    for i in fs.keys():
        page = 1
        stocks = getOnePageStock(fs[i],page,k[i])
        #计算总页数
        total=getHtml(fs[i], 1, k[i])
        totalpage=math.ceil(total[1]/20.0)
        #自动爬取多页,直到结束
        while True:
            page += 1
            if page<=totalpage:
                stocks.extend(getOnePageStock(fs[i], page,k[i]))
                #print(i+"已加载第"+str(page)+"页")
            else:
                break
        df = pd.DataFrame(stocks)
        #提取所要的数据
        df=df.drop([0,7,8,9,10,12,18,19,20,21,22,23,24,25,26,27,28,29,30],axis=1) #去除一些数据,留下需要的列,axis=1是列,=0是行
        #调整一下顺序
        order = [11,13,1,2,3,4,5,6,14,15,16,17]
        df = df[order]
        columns = {11:"代码",13:"名称",1:"最新价",2:"涨跌幅(%)",3:"涨跌额",4:"成交量",5:"成交额",6:"振幅(%)",14:"最高",15:"最低",16:"今开",17:"昨收"}
        #重新给列命名
        df.rename(columns=columns, inplace=True)
        #保存为xls文件
        df.index += 1 #序号从0开头改为从1开头
        df.to_excel("东方财富网股票数据031804112/"+i+".xls",index_label='序号')
        print("已保存"+i+".xls")

main()

运行结果

xls文件不全部截图了

沪深A股

中小板

心得体会

(1)爬取js加载的动态数据,通过抓包获取数据集url,通过对json解析对应数据集。

(2)加深了对dataframe的了解,运用了它的一些方法

(3)正则表达式匹配,对数据处理更熟练了

作业三:

思路

在作业二的基础上进行一些修改和删减就好了

  • 修改的部分:
    设置一个find变量,如果f12的数据等于自选的代码号,则find=1并跳出本页的循环,并且不用翻到下一页。

  • 删减的部分:
    删掉了结构化,保存为xls文件,直接输出在哪里找到的,哪一页,以及股票数据信息。

  • 获取的是代码为'603112'的股票,如果要换别的股票,可以通过修改主函数中的number就可以了

代码

import requests
import re
import math
#用get方法访问服务器并提取页面数据
def getHtml(fs,page,k):
    headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3141.8 Safari/537.36}"
    }
    #页数是通过修改pn值,不同股票的url有两个地方不同,通过之后的字典来实现。
    url = "http://35.push2.eastmoney.com/api/qt/clist/get?cb=jQuery112402976183355999211_1601533720950&pn="+str(page)+"&pz=20&po=1&np=1&ut=bd1d9ddb04089700cf9c27f6f7426281&fltt=2&invt=2&fid=f3&fs="+fs+"&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&_="+k
    r = requests.get(url,headers=headers)
    pat = "\"data\":.*\]"
    data = re.compile(pat, re.S).findall(r.text)
    # 获取数据总条数,用于主函数中计算总页数,每页有20条数据,相除向上取整为总页数。
    t=re.findall(r"\"total\":[\d]*",data[0])
    to=t[0].split(':')
    total=eval(to[1])
    # 去除前面的total和diff数据
    data[0]=data[0][29:]
    return data,total
#获取单个页面股票数据
def getOnePageStock(fs,page,k,number,i):
    data = getHtml(fs,page,k)
    data=data[0]
    datas = data[0].split('},{') #不同股票分割
    stocks = []
    find=0  #设置find来判断是否找到了
    for t in range(len(datas)):
        stock = datas[t].replace('"',"").split(',')#不同信息分割,并且去掉引号
        for j in range(len(stock)):
            # 冒号分割,获取信息的值
            t=stock[j].split(':')
            stock[j]=t[1]
        if stock[11] == number:
            stocks.append(stock)
            find=1 #找到,就可以输出,停止循环了
            print(i)
            print("在第"+str(page)+"页:")
            print("{:4}\t{:4}\t{:4}\t{:4}\t{:4}\t{:4}\t{:4}\t{:4}".format("代码", "名称", "今开", "最高", "最低","涨跌幅","换手率","成交量"))
            print("{:4}\t{:4}\t{:4}\t{:4}\t{:4}\t{:4}\t{:4}\t{:4}".format(stock[11],stock[13],stock[16],stock[14],stock[15],stock[2],stock[7],stock[4]))
            break
    return find
def main():
    fs = {
        "沪深A股":"m:0+t:6,m:0+t:13,m:0+t:80,m:1+t:2,m:1+t:23",
        "上证A股":"m:1+t:2,m:1+t:23",
        "深证A股":"m:0+t:6,m:0+t:13,m:0+t:80",
        "新股":"m:0+f:8,m:1+f:8",
        "中小板":"m:0+t:13",
        "创业板":"m:0+t:80"
    }
    k = {
        "沪深A股": "1601536578738",
        "上证A股": "1601536578736",
        "深证A股": "1601536578759",
        "新股": "1601536578765",
        "中小板": "1601536578882",
        "创业板": "1601536578888"
    }
    #自选三位加学号后三位
    number='603112'
    for i in fs.keys():
        page = 1
        iffind = getOnePageStock(fs[i],page,k[i],number,i)
        #计算总页数
        total=getHtml(fs[i], 1, k[i])
        totalpage=math.ceil(total[1]/20.0)
        #自动爬取多页
        while True:
            page += 1
            if page <= totalpage and iffind !=1: #如果小于总页数,并且没找到,就继续找
                iffind=getOnePageStock(fs[i], page,k[i],number,i)
                #print(i+"已加载第"+str(page)+"页")
            else:
                break
main()

运行结果

心得体会

(1)与作业2相同的一些方法的运用

(2)缺点就是不能动态抓取,比如代码为603112的股票在新股中的位置是不断变化的,输出的所在页数已经是过去的了。

posted @ 2020-10-03 13:12  lumos1  阅读(551)  评论(0编辑  收藏  举报