问题1:通过爬虫爬取链家的新房数据,并进行预处理。要求筛选出房价最高和最低的数据。
问题2:分析已给出的北京市气候数据,求出各年PM平均值和逐月气温和PM值得变化。

1.预处理新房数据

通过爬虫爬取链家的新房数据https://bj.fang.lianjia.com/loupan/,并进行预处理。
• 最终的csv文件,应包括以下字段:名称,地理位置(3个字段分别存储),房型(只保留最小房型),面积(按照最小值),总价(万元,整数),均价(万元,保留小数点后4位);
• 对于所有字符串字段,要求去掉所有的前后空格;
• 如果有缺失数据,不用填充。
• 找出总价最贵和最便宜的房子,以及总价的中位数
• 找出单价最贵和最便宜的房子,以及单价的中位数

1.设计爬虫

关于如何设计爬虫,前一篇博文详细讲述了设计爬虫获取链家二手房数据,在此简略讲述。

链家的页面可以静态获取,因此可以结合Xpath来获取网页内容。设计Item如下:

import scrapy


class LianjiaItem(scrapy.Item):
    name = scrapy.Field()  # 名字
    area = scrapy.Field()  # 位置
    area_detail = scrapy.Field()
    position = scrapy.Field()
    type = scrapy.Field()  # 房型
    square = scrapy.Field()  # 面积
    total = scrapy.Field()  # 总价
    average = scrapy.Field()  # 均价
    pass

然后是设计spider.py文件:

from lianjia.items import LianjiaItem
import scrapy
import re


class mySpider(scrapy.spiders.Spider):
    name = "lianjia"
    allowed_domains = ["bj.lianjia.com/"]
    url = "https://bj.fang.lianjia.com/loupan/pg{}"
    headers = {
        \'User-Agent\': \'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:82.0) Gecko/20100101 Firefox/82.0\',
        \'Accept\': \'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8\',
        \'Accept-Language\': \'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2\',
        \'Connection\': \'keep-alive\',
        \'Upgrade-Insecure-Requests\': \'1\',
        \'Pragma\': \'no-cache\',
        \'Cache-Control\': \'no-cache\',
    }

    def start_requests(self):
        for page in range(1, 6):
            yield scrapy.FormRequest(
                url=self.url.format(page),
                method="GET",
                headers=self.headers,
                callback=self.parse
            )

    def parse(self, response):
        for each in response.xpath("/html/body/div[4]/ul[2]/li"):
            item = LianjiaItem()
            item[\'name\'] = each.xpath("div[1]/div[1]/a[1]/text()").extract()[0]
            item[\'area\'] = each.xpath("div[1]/div[2]/span[1]/text()").extract()[0]
            item[\'area_detail\'] = each.xpath("div[1]/div[2]/span[2]/text()").extract()[0]
            item[\'position\'] = each.xpath("div[1]/div[2]/a[1]/text()").extract()[0]
            item[\'type\'] = each.xpath("div[1]/a[1]/span[1]/text()").extract()
            if len(item[\'type\']) > 0:
                item[\'type\'] = item[\'type\'][0]  # 取户型的最小值
            else:
                item[\'type\'] = \'\'  # 考虑为空的情况
            square = each.xpath("div[1]/div[3]/span/text()").extract()
            if len(square) > 0:
                temp = square[0].split(\'-\')
                item[\'square\'] = re.findall(r\'\d+\', temp[0].split()[1])[0]  # 取面积的最小值
            else:
                item[\'square\'] = \'\'  # 考虑为空的情况
            price = each.xpath("div/div[6]/div[1]/span[2]/text()").extract()[0].strip()
            if price == "元/㎡(均价)":  # 考虑有些数据有总价和均价,而有些只有总价
                item[\'average\'] = each.xpath("div/div[6]/div[1]/span[1]/text()").extract()[0]
                total = each.xpath("div/div[6]/div[2]/text()").extract()
                if len(total) > 0:
                    total = total[0]
                    item[\'total\'] = re.findall(r\'\d+\', total)[0]
                else:
                    item[\'total\'] = \'\'
            else:
                item[\'average\'] = \'\'
                item[\'total\'] = each.xpath("div/div[6]/div[1]/span[1]/text()").extract()[0]
            item[\'total\'] = format(float(item[\'total\']), \'.4f\')  # 按要求将总价保留4位小数,即精确到元
            yield item

然后是设计管道文件,将获取的数据保存为csv文件:

import csv


class LianjiaPipeline(object):
    def open_spider(self,spider):
        try:
            self.file = open(\'data.csv\', \'w\', encoding=\'utf-8\', newline=\'\')
            self.csv = csv.writer(self.file)
            self.csv.writerow([\'name\', \'area\', \'area_detail\',
                               \'position\', \'type\', \'square\', \'average\', \'total\'])
            # 这里是设置表格的抬头,方便后续的数据处理
        except Exception as err:
            print(err)

    def process_item(self, item, spider):
        self.csv.writerow(list(item.values()))
        return item

    def close_spider(self, spider):
        self.file.close()

这里有个有意思的坑,item的写入文件是按代码的处理顺序进行的,也就是说在spider.py中如果先赋值total项(即第一次出现),再赋值average项,那么csv文件中就是这个顺序,反过来处理则在csv文件中先是average项,后是total项。正常来说不会有太大影响,但如果在编写选择结构时,两个项目的赋值顺序在不同分支中有不同,这会导致csv文件里的数据顺序产生不一致,影响后续的处理。

2.处理数据

至此已将数据保存下来,接下来进行数据处理,这里需要使用pandas库:

import numpy as np
import pandas as pd

filename = \'data.csv\'
data_df = pd.read_csv(filename, encoding=\'utf-8\', dtype=str)

# 去掉所有字符串的前后空行
data_df[\'name\'] = data_df[\'name\'].str.strip()
data_df[\'area\'] = data_df[\'area\'].str.strip()
data_df[\'area_detail\'] = data_df[\'area_detail\'].str.strip()
data_df[\'position\'] = data_df[\'position\'].str.strip()
data_df[\'type\'] = data_df[\'type\'].str.strip()

# 修改价格和面积为数字类型
data_df[\'total\'] = data_df[\'total\'].astype(np.float)
data_df[\'average\'] = data_df[\'average\'].astype(np.float)
data_df[\'square\'] = data_df[\'square\'].astype(np.float)

# 找出总价最贵和最便宜的房子,以及总价的中位数
print("总价最贵的房子:")
s = data_df[\'total\']
print(data_df.iloc[s.idxmax()])
print("------------------------------")
print("总价最便宜的房子:")
print(data_df.iloc[s.idxmin()])
print("------------------------------")
print("总价的中位数:")
print(s.median())
print("\n--------------------------------------------\n")

# 找出单价最贵和最便宜的房子,以及单价的中位数

print("单价最贵的房子")
s = data_df[\'average\']
print(data_df.iloc[s.idxmax()])
print("------------------------------")
print("单价最便宜的房子:")
print(data_df.iloc[s.idxmin()])
print("------------------------------")
print("总价的中位数:")
print(s.median())

输出结果如下:

总价最贵的房子:
name                            润泽御府
area                              朝阳
area_detail                       北苑
position       北京市朝阳区北五环顾家庄桥向北约2.6公里
type                              4室
square                           540
average                       100000
total                           5000
Name: 36, dtype: object
------------------------------
总价最便宜的房子:
name                    K2十里春风
area                        通州
area_detail               通州其它
position       永乐店镇漷小路百菜玛工业园对面
type                        2室
square                      74
average                  24500
total                      185
Name: 25, dtype: object
------------------------------
总价的中位数:
725.0

--------------------------------------------

单价最贵的房子
name                                  北京书院
area                                    朝阳
area_detail                           惠新西街
position       北三环以北,惠新东街与北土城东路交汇处西行200米路北
type                                    1室
square                                  67
average                             112000
total                                  750
Name: 11, dtype: object
------------------------------
单价最便宜的房子:
name           奥园北京源墅
area               密云
area_detail      密云其它
position         溪翁庄镇
type               3室
square            120
average         24000
total             270
Name: 27, dtype: object
------------------------------
总价的中位数:
50900.0

进程已结束,退出代码0

2.计算北京空气质量数据

要求:
1.汇总计算PM指数年平均值的变化情况
2.汇总计算10-15年PM指数和温度月平均数据的变化情况

同前一道问题,需要使用pandas对读取到的csv文件进行处理。设计的代码如下:

import numpy as np
import pandas as pd
from pandas import DataFrame

# 读取文件
filename = \'BeijingPM20100101_20151231.csv\'
data_df = pd.read_csv(filename, encoding=\'utf-8\', dtype=str)
# 转换部分列的数据为数字
data_df[\'month\'] = data_df[\'month\'].astype(np.float)
data_df[\'TEMP\'] = data_df[\'TEMP\'].astype(np.float)
data_df[\'PM_Dongsi\'] = data_df[\'PM_Dongsi\'].astype(np.float)
data_df[\'PM_Dongsihuan\'] = data_df[\'PM_Dongsihuan\'].astype(np.float)
data_df[\'PM_Nongzhanguan\'] = data_df[\'PM_Nongzhanguan\'].astype(np.float)
data_df[\'PM_US Post\'] = data_df[\'PM_US Post\'].astype(np.float)
# 求出每行的平均PM,加入数据中成为新的一列
temp_df = data_df.loc[:, [\'PM_Dongsi\', \'PM_Dongsihuan\', \'PM_Nongzhanguan\', \'PM_US Post\']]
data_df[\'PM\'] = temp_df.apply(lambda x: x.mean(), axis=1)
# print(data_df)

# 利用处理好的PM数据,求出各年的PM变化量
temp_df = data_df.loc[:, [\'year\', \'PM\']]
years = [\'2010\', \'2011\', \'2012\', \'2013\', \'2013\', \'2014\', \'2015\']
result1 = {\'year\': [], \'PM\': []}
for year in years:
    df = temp_df[temp_df.year == year]
    # print(df[\'PM\'].mean(axis=0))
    result1[\'year\'].append(year)
    result1[\'PM\'].append(df[\'PM\'].mean(axis=0))
f1 = DataFrame(result1)
print("汇总计算PM指数年平均值的变化情况,可查看problem1.csv:")
print(f1)
f1.to_csv(\'problem1.csv\')
print("\n---------------------------------------\n")

# 计算各年各月的PM指数和温度的平均数据
temp_df = data_df.loc[:, [\'year\', \'month\', \'TEMP\', \'PM\']]
result2 = {\'year\': [], \'month\': [], \'TEMP\': [], \'PM\': []}
for year in years:
    df_year = temp_df[temp_df.year == year]
    for month in range(1, 13):
        df = df_year[df_year.month == month]
        result2[\'year\'].append(year)
        result2[\'month\'].append(month)
        result2[\'TEMP\'].append(df[\'TEMP\'].mean(axis=0))
        result2[\'PM\'].append(df[\'PM\'].mean(axis=0))
f2 = DataFrame(result2)
print(\'汇总计算各月气温和PM指数平均值的变化情况,可查看problem2.csv:\')
print(f2)
f2.to_csv(\'problem2.csv\')

打印结果如下:

汇总计算PM指数年平均值的变化情况,可查看problem1.csv:
   year          PM
0  2010  104.045730
1  2011   99.093240
2  2012   90.538768
3  2013   98.402664
4  2013   98.402664
5  2014   93.917704
6  2015   85.858942

---------------------------------------

汇总计算各月气温和PM指数平均值的变化情况,可查看problem2.csv:
    year  month       TEMP          PM
0   2010      1  -6.162634   90.403670
1   2010      2  -1.922619   97.239940
2   2010      3   3.293011   94.046544
3   2010      4  10.806944   80.072423
4   2010      5  20.831989   87.071913
..   ...    ...        ...         ...
79  2015      8  25.829071   45.896057
80  2015      9  20.408333   50.924769
81  2015     10  13.827957   77.257841
82  2015     11   2.897079  125.803125
83  2015     12  -0.617766  162.178987

[84 rows x 4 columns]

进程已结束,退出代码0

版权声明:本文为pingxinwen原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/pingxinwen/p/14027734.html