数据爬虫 + 数据清洗 + 数据可视化,完整的项目教程!

390 篇文章 2 订阅
276 篇文章 4 订阅

一:数据挖掘

我选用了链家网做数据爬取场所(不得不唠叨一句,这个网站真是为了爬虫而生的,对爬虫特别友好哈哈哈,反扒措施比较少)

比如我们爬取贵阳市乌当区的所有房子的房价及其他信息:

比如我们爬取第一个房子的价格:115万:

接下来我们可以使用复制CSS选择器或者XPath等等来实现获取:

下面我们使用复制XPath的方式,修改路径即可(需要一定前端知识)

分别实现详解:

1:导入必备库

import requests
from lxml import etree
import xlwt
from xlutils.copy import copy
import xlrd
import csv
import pandas as pd
import time

细说一下:
Requests 是用Python语言编写,基于 urllib,采用 Apache2 Licensed 开源协议的 HTTP 库,爬虫必备技能之一。它比 urllib 更加方便,可以节约我们大量的工作,完全满足 HTTP 测试需求。Requests 的哲学是以 PEP 20 的习语为中心开发的,所以它比 urllib 更加 Pythoner。更重要的一点是它支持 Python3 哦!

Pandas是python第三方库,提供高性能易用数据类型和分析工具 , pandas是一个强大的分析结构化数据的工具集;它的使用基础是Numpy(提供高性能的矩阵运算);用于数据挖掘和数据分析,同时也提供数据清洗功能。

2:定义爬取URL地址和设置请求头(其实还可以更完善,不过链家网比较友善,这点够用了)

        self.url = 'https://gy.lianjia.com/ershoufang/wudangqu/pg{}/'
        self.headers = {
            "User-Agent": "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36"}

url是要获取信息的地址:我们选用贵阳市(gy)乌当区(wudangqu)为目标,然后pg{}是页码的意思:pg100就是爬第一百页,这里我们使用{}做一下占位,方便后续从第一页迭代到最后。

headers是我们的请求头,就是模拟人正常登录的意思,而不是通过python,让网页知道你是爬虫,知道了就有可能封掉你的IP等。 通常HTTP消息包括客户机向服务器的请求消息和服务器向客户机的响应消息。这两种类型的消息由一个起始行,一个或者多个头域,一个只是头域结束的空行和可 选的消息体组成。HTTP的头域包括通用头,请求头,响应头和实体头四个部分。每个头域由一个域名,冒号(:)和域值三部分组成。域名是大小写无关的,域 值前可以添加任何数量的空格符,头域可以被扩展为多行,在每行开始处,使用至少一个空格或制表符。 User-Agent头域的内容包含发出请求的用户信息。

3:使用Requests获取数据

    def get\_response\_spider(self, url\_str):  # 发送请求
        get\_response = requests.get(self.url, headers=self.headers)
        time.sleep(4)
        response = get\_response.content.decode()
        html = etree.HTML(response)
        return html

4:使用Xpath筛选数据源,过程见上图,需要一定的前端知识,不过,也有一些技巧:

    def get\_content\_html(self, html):  # 使xpath获取数据
        self.houseInfo = html.xpath('//div\[@class="houseInfo"\]/text()')
        self.title = html.xpath('//div\[@class="title"\]/a/text()')
        self.positionInfo = html.xpath('//div\[@class="positionInfo"\]/a/text()')
        self.totalPrice = html.xpath('//div\[@class="totalPrice"\]/span/text()')
        self.unitPrice = html.xpath('//div\[@class="unitPrice"\]/span/text()')
        self.followInfo = html.xpath('//div\[@class="followInfo"\]/text()')
        self.tag = html.xpath('//div\[@class="tag"\]/span/text()')

5:使用生成器,通过for循环和yield生成器迭代生成数据项:

    def xpath\_title(self):
        for i in range(len(self.title)):
            yield self.title\[i\]

    def xpath\_positionInfo(self):
        for i in range(len(self.positionInfo)):
            yield self.positionInfo\[i\]

    def xpath\_totalPrice(self):
        for i in range(len(self.totalPrice)):
            yield self.totalPrice\[i\]
    def xpath\_unitPrice(self):
        for i in range(len(self.unitPrice)):
            yield self.unitPrice\[i\]
    def xpath\_followInfo(self):
        for i in range(len(self.followInfo)):
            yield self.followInfo\[i\]
    def xpath\_tag(self):
        for i in range(len(self.tag)):
            yield self.tag\[i\]

6:通过调用这些函数进行预获得:

self.xpath\_houseInfo()
        self.xpath\_title()
        self.xpath\_positionInfo()
        self.xpath\_totalPrice()
        self.xpath\_unitPrice()
        self.xpath\_followInfo()
        self.xpath\_tag()
        get\_houseInfo = self.xpath\_houseInfo()
        get\_title = self.xpath\_title()
        get\_positionInfo=self.xpath\_positionInfo()
        get\_totalPrice = self.xpath\_totalPrice()
        get\_unitPrice = self.xpath\_unitPrice()
        get\_followInfo=self.xpath\_followInfo()
        get\_tag=self.xpath\_tag()

这里的函数就是调用上面的生成器的函数:
生成器yield 理解的关键在于:下次迭代时,代码从yield的下一跳语句开始执行。

7:数据筛选,写入文本中:

        while True:
            data\_houseInfo= next(get\_houseInfo)
            data\_title=next(get\_title)
            data\_positionInfo=next(get\_positionInfo)
            data\_totalPrice=next(get\_totalPrice)
            data\_unitPrice=next(get\_unitPrice)
            data\_followInfo=next(get\_followInfo)
            data\_tag=next(get\_tag)

            with open("lianjia1.csv", "a", newline="", encoding="utf-8-sig") as f:
                fieldnames = \['houseInfo', 'title', 'positionInfo', 'totalPrice/万元', 'unitPrice', 'followInfo', 'tag'\]
                writer = csv.DictWriter(f, fieldnames=fieldnames)  # 写入表头
                writer.writeheader()
                list\_1 = \['houseInfo', 'title', 'positionInfo', 'totalPrice/万元', 'unitPrice', 'followInfo', 'tag'\]
                list\_2 = \[data\_houseInfo,data\_title,data\_positionInfo,data\_totalPrice,data\_unitPrice,data\_followInfo,data\_tag\]
                list\_3 = dict(zip(list\_1, list\_2))
                writer.writerow(list\_3)
                print("写入第"+str(i)+"行数据")
            i += 1
            if i > len(self.houseInfo):
                break

8:这里用过Next方法对生成器中内容不断提取:

fieldnames = \['houseInfo', 'title', 'positionInfo', 'totalPrice/万元', 'unitPrice', 'followInfo', 'tag'\]
writer = csv.DictWriter(f, fieldnames=fieldnames)  # 写入表头
writer.writeheader()

9:将其加在表头中。然后每一行写入一次数据

10:最后构造run函数:

    def run(self):
        i = 1
        while True:
            url\_str = self.url.format(i)  # 构造请求url
            html = self.get\_response\_spider(url\_str)
            self.get\_content\_html(html)
            self.qingxi\_data\_houseInfo()

            i += 1
            if i == 57:  
                break

11:循环迭代一下,将上述的page页码从一到最后

12:main函数中启动一下,先new一下这个类,再启动run函数,就会开始爬取了

然后我们看一下结果:

然后爬虫阶段就结束了,当然也可以写入数据库中,我们保存在文本文件中是为了更方便。我们保存在了左边的csv文件中,是不是很简单~,源码这个网上应该也有,我就暂时不放了,等朋友毕业再发

二:数据清洗与提取

1:首先导入一下需要的库

"""
数据分析及可视化
"""
import pandas as pd
from pyecharts.charts import Line, Bar
import numpy as np
from pyecharts.globals import ThemeType
from pyecharts.charts import Pie
from pyecharts import options as opts

2:数据全局定义:

places = \['lianjia\_BaiYunQu', 'lianjia\_GuanShanHuQu', 'lianjia\_HuaXiQu', 'lianjia\_NanMingQu', 'lianjia\_WuDangQu', 'lianjia\_YunYanQu'\]
place = \['白云区', '观山湖区', '花溪区', '南明区', '乌当区', '云岩区'\]
avgs = \[\]  # 房价均值
median = \[\]  # 房价中位数
favourate\_avg = \[\]  # 房价收藏人数均值
favourate\_median = \[\]  # 房价收藏人数中位数
houseidfo = \['2室1厅', '3室1厅', '2室2厅', '3室2厅', '其他'\]  # 房型定义
houseidfos = \['2.1', '3.1', '2.2', '3.2'\]  
sum\_house = \[0,  0, 0, 0, 0\]  # 各房型数量
price = \[\]  # 房价
fav = \[\]  # 收藏人数
type = \[\]  
area = \[\]  # 房间面积

注释写的很清楚了,我的places是为了方便读取这几个csv中文件各自保存的数据(‘白云区’, ‘观山湖区’, ‘花溪区’, ‘南明区’, ‘乌当区’, '云岩区’区的数据):

3:文件操作,打开文件:

def avg(name):
	df = pd.read\_csv(str(name)+'.csv', encoding='utf-8')
    pattern = '\\d+'
    df\['totalPrice/万元'\] = df\['totalPrice/万元'\].str.findall(pattern) # 转换成字符串,并且查找只含数字的项
    df\['followInfo'\] = df\['followInfo'\].str.findall(pattern)
    df\['houseInfo'\] = df\['houseInfo'\].str.findall(pattern)

使用padas的read_csv方式读取csv文件 name以传参形式迭代传入,也就是一个区一个区的传入主要是为了减少代码量,增加审美。就不必每一次都写几十行代码了

然后是一些匹配,转换成字符串,并且查找只含数字的项。

    for i in range(len(df)):
        if (i + 1) % 2 == 0:
            continue
        else:
            if len(df\['totalPrice/万元'\]\[i\]) == 2:
                avg\_work\_year.append(','.join(df\['totalPrice/万元'\]\[i\]).replace(',', '.'))
                medians.append(float(','.join(df\['totalPrice/万元'\]\[i\]).replace(',', '.')))
                price.append(','.join(df\['totalPrice/万元'\]\[i\]).replace(',', '.'))
            if len(df\['followInfo'\]\[i\]) ==2:
                favourates.append(int(','.join(df\['followInfo'\]\[i\]\[:1\])))
                fav.append(int(','.join(df\['followInfo'\]\[i\]\[:1\])))
            if float(','.join(df\['houseInfo'\]\[i\]\[:2\]).replace(',', '.')) == 2.1:
                k +=1
                sum\_houses\[0\] =k
                type.append(2.1)
            if float(','.join(df\['houseInfo'\]\[i\]\[:2\]).replace(',', '.')) == 3.1:
                k1 +=1
                sum\_houses\[1\] =k1
                type.append(3.1)
            if float(','.join(df\['houseInfo'\]\[i\]\[:2\]).replace(',', '.')) == 2.2:
                k3 +=1
                sum\_houses\[2\] =k3
                type.append(2.2)
            if float(','.join(df\['houseInfo'\]\[i\]\[:2\]).replace(',', '.')) == 3.2:
                k4 +=1
                sum\_houses\[3\] =k4
                type.append(3.2)
            else:
                k4 +=1
                sum\_houses\[4\] = k4
                type.append('other')
            area.append(float(','.join(df\['houseInfo'\]\[i\]\[2:4\]).replace(',', '.')))
    sum\_house\[0\] =sum\_houses\[0\]
    sum\_house\[1\] = sum\_houses\[1\]
    sum\_house\[2\] = sum\_houses\[2\]
    sum\_house\[3\] = sum\_houses\[3\]
    sum\_house\[4\] = sum\_houses\[4\]

    favourates.sort()
    favourate\_median.append(int(np.median(favourates)))
    medians.sort()
    median.append(np.median(medians))
    # price = avg\_work\_year
    b = len(avg\_work\_year)
    b1= len(favourates)

    sum = 0
    sum1 = 0
    for i in avg\_work\_year:
        sum = sum+float(i)
    avgs.append(round(sum/b, 2))
    for i in favourates:
        sum1 = sum1+float(i)
    favourate\_avg.append(round(int(sum1/b1), 2))

4:这里是数据筛选的核心部分,我们细说一下:

		if len(df\['totalPrice/万元'\]\[i\]) == 2:
                avg\_work\_year.append(','.join(df\['totalPrice/万元'\]\[i\]).replace(',', '.'))
                medians.append(float(','.join(df\['totalPrice/万元'\]\[i\]).replace(',', '.')))
                price.append(','.join(df\['totalPrice/万元'\]\[i\]).replace(',', '.'))

5:这里是获取总价格,并且清洗好,放入前面定义好的数组中,保存好,

if len(df\['followInfo'\]\[i\]) ==2:
                favourates.append(int(','.join(df\['followInfo'\]\[i\]\[:1\])))
                fav.append(int(','.join(df\['followInfo'\]\[i\]\[:1\])))

6:这里是获取总收藏人数,并且清洗好,放入前面定义好的数组中,保存好,

if len(df\['followInfo'\]\[i\]) ==2:
                favourates.append(int(','.join(df\['followInfo'\]\[i\]\[:1\])))
                fav.append(int(','.join(df\['followInfo'\]\[i\]\[:1\])))
            if float(','.join(df\['houseInfo'\]\[i\]\[:2\]).replace(',', '.')) == 2.1:
                k +=1
                sum\_houses\[0\] =k
                type.append(2.1)
            if float(','.join(df\['houseInfo'\]\[i\]\[:2\]).replace(',', '.')) == 3.1:
                k1 +=1
                sum\_houses\[1\] =k1
                type.append(3.1)
            if float(','.join(df\['houseInfo'\]\[i\]\[:2\]).replace(',', '.')) == 2.2:
                k3 +=1
                sum\_houses\[2\] =k3
                type.append(2.2)
            if float(','.join(df\['houseInfo'\]\[i\]\[:2\]).replace(',', '.')) == 3.2:
                k4 +=1
                sum\_houses\[3\] =k4
                type.append(3.2)
            else:
                k4 +=1
                sum\_houses\[4\] = k4
                type.append('other')
            area.append(float(','.join(df\['houseInfo'\]\[i\]\[2:4\]).replace(',', '.')))

7:这里是获取房型和面积,清洗好,放入数组中

    favourates.sort()
    favourate\_median.append(int(np.median(favourates)))
    medians.sort()
    median.append(np.median(medians))
    # price = avg\_work\_year
    b = len(avg\_work\_year)
    b1= len(favourates)

    sum = 0
    sum1 = 0
    for i in avg\_work\_year:
        sum = sum+float(i)
    avgs.append(round(sum/b, 2))
    for i in favourates:
        sum1 = sum1+float(i)
    favourate\_avg.append(round(int(sum1/b1), 2))

8:这里是把上面的信息加工,生成平均数,中位数等。

另外说一下,清洗过程:
’,’.join()是为了筛选出的信息不含中括号和逗号

df[‘houseInfo’][i][2:4]是为了取出相应的数据,使用了python的切片操作

.replace(’,’, ‘.’)是把逗号改成小数点,这样就是我们想要的结果了。

下面执行看一下结果:

数据筛选结束~

读者福利:知道你对Python感兴趣,便准备了这套python学习资料

对于0基础小白入门:

如果你是零基础小白,想快速入门Python是可以考虑的。
一方面是学习时间相对较短,学习内容更全面更集中。
二方面是可以找到适合自己的学习方案

包括:Python激活码+安装包、Python web开发,Python爬虫,Python数据分析,人工智能、机器学习等习教程。带你从零基础系统性的学好Python!

👉Python学习路线汇总👈

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。(全套教程文末领取哈)
在这里插入图片描述

👉Python必备开发工具👈

在这里插入图片描述

温馨提示:篇幅有限,已打包文件夹,获取方式在:文末

👉Python学习视频600合集👈

观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
在这里插入图片描述

👉实战案例👈

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。
在这里插入图片描述

👉100道Python练习题👈

检查学习结果。
在这里插入图片描述

👉面试刷题👈

在这里插入图片描述

在这里插入图片描述

👉python副业兼职与全职路线👈

在这里插入图片描述
上述这份完整版的Python全套学习资料已经上传CSDN官方,如果需要可以微信扫描下方CSDN官方认证二维码 即可领取

👉[[CSDN大礼包:《python安装包&全套学习资料》免费分享]]安全链接,放心点击

  • 2
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值