作者 | 月小水长
责编 | 伍杏玲

2019程序员转型学什么?

https://edu.csdn.net/topic/ai30?utm_source=csdn_bw

通过分页、线程池、代理池等技术,快速爬取链家网近4万条在售二手房信息,速度可达 10000 条 / 5 分钟。

通过对二手房作数据分析,得到北上广深等(新)一线城市四地房价的纵向比较,同时对各个城市各个区的房价做横向对比,并将对比结果可视化出来。

主要用到的库或模块包括 Requests、PyQuery、ThreadPoolExecutor、JSON、Matplotlib、PyEcharts。

环境:Widnows10、Python3.5、Pycharm2018。

数据抓取

爬虫架构设计

通过分析链家网的 URL ,不难发现,每一个城市的链家网的基本格式是:

城市名简拼 + ”.lianjia.com“

所以整个爬虫最外层应该是遍历一个保存城市简拼的列表,拼接得到一个个起始 URL,根据这些 URL 爬取对应城市的链家网。

针对每一个城市的链家网而言,首先得到该城市在售二手房的总套数,由于每一页显示的套数是 30,由总套数整除以30再加上1可以得到总页数,但是由于最大可浏览页数为 100,所以我们这里得加个判断,如果总页数大于 100 的话,令总页数等于 100。

分析具体城市的链家网每一页的 URL, 以北京为例,我们可以发现第 N 页的 URL 是:

bj.lianjia.com/ershoufang/pg{N},由此我们可以通过以下代码来得到每一页的 URL:

 
 

for i in range(total_page):
    page_url = "bj.lianjia.com/ershoufang/pg{}".format(i+1)

本来得到每一页的 URL 后,我们可以得到该页上 30 套房的房价信息和详情页 URL,但是页面上没有房子所在区的信息。

我们只能再向下请求访问详情页 URL,从而提取出我们想要的所有数据。

综上所述,我们可以将整个框架从上往下分为四层,如下图所示:

基于上述思路,在写代码的时候,可以分层从上往下实现,方便调试。

第一层 & 第二层:获取总套数

根据城市简拼得到起始 URL,并得到总套数,为分页做准备。

 
 

def get_list_page_url(city):

start_url = "https://{}.lianjia.com/ershoufang".format(city)
    headers =  {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
    }
    try:
        response = requests.get(start_url, headers=headers)
        # print(response.status_code, response.text)
        doc = pq(response.text)
        total_num =  int(doc(".resultDes .total span").text())
        total_page = total_num // 30 + 1
        # 只能访问到前一百页
        if total_page > 100:
            total_page = 100

page_url_list = list()

for i in range(total_page):
            url = start_url + "/pg" + str(i + 1) + "/"
            page_url_list.append(url)
            #print(url)
        return page_url_list

except:
        print("获取总套数出错,请确认起始URL是否正确")
        return None

第三层:根据起始 URL 得到分页 URL

 
 

def get_detail_page_url(page_url):
    global detail_list
    headers =  {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Safari/537.36',
        'Referer': 'https://bj.lianjia.com/ershoufang'
    }

try:
        response = requests.get(page_url,headers=headers,timeout=3)
        doc = pq(response.text)
        i = 0
        detail_urls = list()
        for item in doc(".sellListContent li").items():
            i += 1
            print(i)
            if i == 31:
                break
            child_item = item(".noresultRecommend")
            if child_item == None:
                i -= 1
            detail_url = child_item.attr("href")
            detail_urls.append(detail_url)
        return detail_urls
    except:
        print("获取列表页" + page_url + "出错")

第四层

本层做的是具体解析,解析使用的是 PyQuery 库,支持 CSS 选择器且比 Beautiful Soup 方便。仅仅需要下面几行代码就帮助我们获得了目标数据:

 
 

response = requests.get(url=detail_url, headers=headers, proxies=proxies)
#detail_url 是得到的详情页 URL
detail_dict = dict()
doc = pq(response.text)
unit_price = doc(".unitPriceValue").text()
unit_price = unit_price[0:unit_price.index("元")]
title = doc("h1").text()
area = doc(".areaName .info a").eq(0).text().strip()
url = detail_url

多线程爬取

由于待爬取的数据量巨大,使用单线程速度太慢,最开始采用了第三方库 ThreadPool 来实现多线程,后来了解到 Python3.5 的内置包 concurrent.futures,使用里面的 ThreadPoolExecutor 来实现多线程,速度又提升了 20% 以上。

 
 

p = ThreadPoolExecutor(30)
for page_url in page_url_list:
    p.submit(get_detail_page_url, page_url).add_done_callback(detail_page_parser)
p.shutdown()

第 1 行通过构造函数新建了线程池对象,最大可并发线程数指定为 30,如不指定,其默认值是 CPU 数的 5 倍,第 2、3 行依次把爬取的任务提交到线程池中,并设置回调函数,这里的回调函数拿到的是一包含 get_detail_page_url 返回值的对象。

并把这个对象作为回调函数的参数 res,先把返回的res得到一个结果,即在前面加上一个res.result(),这个结果就是 get_detail_page_url 的返回值。

IP 代理池

由于爬取的数量大,同时由于多线程提高了速度,链家网会拒绝访问,这时可通过代理 IP 来访问,这里使用已经有的轮子,源码链接附在文末。

下载后新开一个 Pycharm 视窗运行该项目,然后我们可以用下面的方式来获取可用的代理 IP:

 
 

def get_valid_ip():
    url = "http://localhost:5000/get"
    try:
        ip = requests.get(url).text
        return ip
    except:
        print("请先运行代理池")

然后通过参数设置使用代理 IP:

 
 

proxies = {
    "http": "http://" + get_valid_ip(),
}
response = requests.get(url=detail_url, headers=headers, proxies=proxies)

数据保存

采用 JSON文件形式保存数据,每个城市保存一个 JSON 文件,文件名为该城市简拼。

 
 

def save_data(data,filename):
    with open(filename+".json", 'w', encoding="utf-8") as f:
        f.write(json.dumps(data, indent=2, ensure_ascii=False))

稍等一会儿,所有数据就保存在本地了:

本爬虫所爬数据仅为本人测试,严禁商用。

数据分析

数据整合

在这里做一些求同地区房价最大值、最小值、平均值,以及数据格式统一化的工作:

 
 

def split_data():
    global region_data
    region_data = dict()
    for region in dic_data.keys():
        # 最大值、最小值、平均值
        region_data[region] = {"max":dic_data[region][0],"min":dic_data[region][0],"average":0}
        for per_price in dic_data[region]:
            if per_price > region_data[region]["max"]:
                region_data[region]["max"] = per_price
            if per_price < region_data[region]["min"]:
                region_data[region]["min"] = per_price
            region_data[region]["average"] += per_price
        region_data[region]["average"] /= len(dic_data[region])
        # 保留两位小数
        region_data[region]["average"] = round(region_data[region]["average"],2)

数据可视化

将分析结果通过 Matplotlib 直观的体现出来,该部分的代码如下:

 
 

def data_viewer():
    label_list = region_data.keys()  # 横坐标刻度显示值
    max = []
    min = []
    average = []
    for label in label_list:
        max.append(region_data[label].get("max"))
        min.append(region_data[label].get("min"))
        average.append(region_data[label].get("average"))
    x = range(len(max))
    """
    绘制条形图
    left: 长条形中点横坐标
    height: 长条形高度
    width: 长条形宽度,默认值0
    .8
    label: 为后面设置legend准备
    """
    rects1 = plt.bar(x=x, height=max, width=0.25, alpha=0.8, color='red', label="最大值")
    rects2 = plt.bar(x=[i + 0.25 for i in x], height=average, width=0.25, color='green', label="平均值")
    rects3 = plt.bar(x=[i + 0.5 for i in x], height=min, width=0.25, color='blue', label="最小值")
    #plt.ylim(0, 50) # y轴取值范围
    plt.ylabel("房价/元")
    """
    设置x轴刻度显示值
    参数一:中点坐标
    参数二:显示值
    """
    plt.xticks([index + 0.2 for index in x], label_list)
    plt.xlabel("地区")
    plt.legend()
    for rect in rects1:
        height = rect.get_height()
        plt.text(rect.get_x() + rect.get_width() / 2, height+1, str(height), ha="center", va="bottom")
    for rect in rects2:
        height = rect.get_height()
        plt.text(rect.get_x() + rect.get_width() / 2, height + 1, str(height), ha="center", va="bottom")
    for rect in rects3:
        height = rect.get_height()
        plt.text(rect.get_x() + rect.get_width() / 2, height + 1, str(height), ha="center", va="bottom")
    plt.show()

结果如下:

限于篇幅,其他城市的图就不放了。

再来看全国主要一线城市二手房房价有序条形图:

可以看出,北京、上海、深圳的房价大致在同一水平线,而厦门位于第四,广州在第六,最后看一下房价地域图:

最后看一下房价地域图这是基于 JavaScript 的可交互动态图,放截图挺别扭的,我已经把它放在我的网上了,感兴趣的可以点击在线观看。

作者简介:月小水长,某 985 计算机学院在校生,熟悉 C++、Java、Python 等多种语言,有大型软件项目开发经验,致力于安卓、计算机视觉、爬虫、数据可视化开发,同时也是业余的前端爱好者。

微信公众号:inspurer

源码:https://github.com/Python3Spiders/LianJiaSpider.git

动态图展示:https://inspurer.github.io/fang_price_city.html

【完】

 热 文

全面学python的时代,作为程序员你怎么看?

https://edu.csdn.net/topic/python115?utm_source=csdn_bw

 推 荐  

☞ 光凭 5G 根本无法解决宽带问题!

☞ 爬取 4400 条淘宝洗发水数据,拯救你的发际线!(附代码和数据集)

☞ 如今,你感受到内存技术的“思维速度”了吗?

☞ 程序员写代码没激情该怎么破?

☞ 跨界打击, 23秒绝杀700智能合约! 41岁遗传学博士研究一年,给谷歌祭出秘密杀器!

☞ 90后美女学霸传奇人生:出身清华姚班,成斯坦福AI实验室负责人高徒

☞ 神操作!这段代码让程序员躺赚200万?给力!

 

print_r('点个好看吧!');
var_dump('点个好看吧!');
NSLog(@"点个好看吧!");
System.out.println("点个好看吧!");
console.log("点个好看吧!");
print("点个好看吧!");
printf("点个好看吧!\n");
cout << "点个好看吧!" << endl;
Console.WriteLine("点个好看吧!");
fmt.Println("点个好看吧!");
Response.Write("点个好看吧!");
alert("点个好看吧!")
echo "点个好看吧!"

点击阅读原文,输入关键词,即可搜索您想要的 CSDN 文章。

喜欢就点击“好看”吧!

Python 爬取分析全国 12 个城市 4 万条房价信息,告诉你该怎样买房?相关推荐

  1. python房价数据分析统计服_Python 爬取分析全国 12 个城市 4 万条房价信息,告诉你该怎样买房?...

    原标题:Python 爬取分析全国 12 个城市 4 万条房价信息,告诉你该怎样买房? 作者 | 月小水长 责编 | 伍杏玲通过分页.线程池.代理池等技术,快速爬取链家网近4万条在售二手房信息,速度可 ...

  2. 你的城市撒币了吗?Python 爬取分析全国消费券发放数据

    作者 | 刘早起 来源 | 早起Python(ID: zaoqi-python) 近期,全国多地以各种形式投放消费券.消费补贴来鼓励消费,部分城市在首期消费券的基础上,连续追加发放多期消费券.你在的城 ...

  3. 实战 | 用Python爬取《云南虫谷》3.6万条评论,并做数据统计可视化展示分析,好看!...

    最近鬼吹灯系列网剧<云南虫谷>上线,作为鬼吹灯系列作品,承接上部<龙岭迷窟>内容,且还是铁三角原班人马主演,网友直呼非常好看! 今天,我们就用Python爬取目前全部剧集的评论 ...

  4. 实战|用Python爬取《云南虫谷》3.6万条评论,并做数据统计可视化展示分析,好看!

    大家好,我是才哥. 最近鬼吹灯系列网剧<云南虫谷>上线,作为鬼吹灯系列作品,承接上部<龙岭迷窟>内容,且还是铁三角原班人马主演,网友直呼非常好看! 今天,我们就用Python爬 ...

  5. python爬取旅游信息_用Python爬取分析全国旅游数据-Go语言中文社区

    前言: Python对于本人来讲也是一个在逐渐学习掌握的过程,这次的内容就从旅游开始讲起,进入正文前首先附(fang)上(du)最令我垂涎欲滴的海鲜盛宴. 数据爬取: 最近几天朋友圈被大家的旅行足迹刷 ...

  6. 用Python爬取分析全国旅游数据

    前言: Python对于本人来讲也是一个在逐渐学习掌握的过程,这次的内容就从旅游开始讲起,进入正文前首先附(fang)上(du)最令我垂涎欲滴的海鲜盛宴. 数据爬取: 最近几天朋友圈被大家的旅行足迹刷 ...

  7. 用Python爬取了全国近5000家旅游景点,分析国庆去哪玩

    双节同庆,小长假如约而至 我想今年大家在家都憋坏了 这么长的假期,当然是出去 玩玩玩! 每当长假的时候,有没有想起被人山人海支配的恐惧! 该去哪些地方呢? 我用 Python 爬取了全国近 5000 ...

  8. python爬取旅游信息_用Python爬取了全国近5000家旅游景点,分析国庆去哪玩

    2020 国庆马上就要到了 我想今年大家在家都憋坏了 今年国庆和中秋刚好又是同一天,加起来有 8 天假 这么长的假期,当然是出去 玩玩玩! 但是每次长假期间,你有没有想起被人山人海支配的恐惧呢? 那么 ...

  9. 国庆去哪玩?用Python爬取了全国5000家旅游景区(记得收藏)

    2020 国庆马上就要到了 我想今年大家在家都憋坏了 今年国庆和中秋刚好又是同一天,加起来有 8 天假 这么长的假期,当然是出去 玩玩玩! 但是每次长假期间,你有没有想起被人山人海支配的恐惧呢? 那么 ...

最新文章

  1. Java内存模型(转载)
  2. Redis可视化工具 Redis Desktop Manager
  3. Js让静态人物动起来Demo演示
  4. http://www.gov.cn/fuwu/bm/gyhxxhb/index.htm
  5. 这是一份通俗易懂的知识图谱技术与应用指南(转)
  6. 一些python函数及其用法
  7. HDU 5617 Jam's maze dp+滚动数组
  8. 与自定义词典 分词_使用jieba库进行中文分词、关键词提取、添加自定义的词典进行分词...
  9. Python 和 R 数据分析/挖掘工具互查
  10. ros melodic控制真实机械臂之moveit_setup_assistant配置
  11. c语言file_C语言程序的编译和调试
  12. mac下使用自带的svn客户端上传、下载文件到服务端
  13. 第一次滑雪小记——杭州临安大明山滑雪场
  14. 中国十大悍匪排行榜,屌爆了!!!!
  15. 《C语言及程序设计》实践参考——n=a!+b!+c!
  16. 网络请求数据demo
  17. oracle表空间扩容asm,oracle表空间文件系统迁移到ASM
  18. LabVIEW编程基础:顺序结构编程
  19. html5如何让多张图片重叠,HTML5图片层叠
  20. windows核心宝藏

热门文章

  1. 会声会影x4素材_如何利用会声会影制作抖音短视频
  2. Web接收实时视频流并显示(flask创建路由接收)| 解决延时不同步问题
  3. 第三章:变量与字符串等基础知识
  4. 常见十大排序算法--python3实现
  5. Go语言struct{}类型的channel
  6. Python3 openpyxl库
  7. Charles安装与入门
  8. Flutter进阶—布局一个控件
  9. mysql event 变量_DQL--select和MySQL的Event
  10. iphone7计算机隐藏,Iphone7:3Dtouch5个隐藏小功能,你知道吗?