【Python爬虫】整站40万条房价数据并行抓取,可更换抓取城市

news2024/11/15 21:40:58

目录

  • 前言
    • 一、获取索引
      • 一级位置:区域信息
      • 二级位置:板块信息
      • 三级位置:地铁信息(搜索地铁周边房源信息)
    • 二、获取索引页最大页数
    • 三、抓取房源信息Tag
    • 四、分配任务,并行抓取
    • 五、将抓取结果存储到excel中,等待可视化数据化处理
  • 总结:


点此跳转领取

相关的一些资料文件、还有代码文件都在文末直接找到拿就行~ 记得点赞支持一下啊~

在这里插入图片描述

前言

这次的爬虫是关于房价信息的抓取,目的在于练习10万以上的数据处理及整站式抓取。

数据量的提升最直观的感觉便是对函数逻辑要求的提高,针对Python的特性,谨慎的选择数据结构。以往小数据量的抓取,即使函数逻辑部分重复,I/O请求频率密集,循环套嵌过深,也不过是1~2s的差别,而随着数据规模的提高,这1 ~2的差别就有可能扩展成为h。

因此对于要抓取数据量较多的网站,可以从两方面着手降低抓取信息的时间成本。

1)优化函数逻辑,选择适当的数据结构,符合Pythonic的编程习惯。例如,字符串的合并,使用join()要比“+”节省内存空间。

2)依据I/O密集与CPU密集,选择多线程、多进程并行的执行方式,提高执行效率。# 一、pandas是什么?
示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

一、获取索引

包装请求request,设置超时timeout

# 获取列表页面
def get_page(url):
    headers = {
        'User-Agent': r'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) '
                      r'Chrome/45.0.2454.85 Safari/537.36 115Browser/6.0.3',
        'Referer': r'http://bj.fangjia.com/ershoufang/',
        'Host': r'bj.fangjia.com',
        'Connection': 'keep-alive'
    }
    timeout = 60
    socket.setdefaulttimeout(timeout)  # 设置超时
    req = request.Request(url, headers=headers)
    response = request.urlopen(req).read()
    page = response.decode('utf-8')
    return page

一级位置:区域信息

在这里插入图片描述

二级位置:板块信息

在这里插入图片描述
以dict方式存储,可以快速的查询到所要查找的目标。-> {‘朝阳’:{‘工体’,‘安贞’,‘健翔桥’…}}

三级位置:地铁信息(搜索地铁周边房源信息)

在这里插入图片描述
将所属位置地铁信息,添加至dict中。 -> {‘朝阳’:{‘工体’:{‘5号线’,‘10号线’ , ‘13号线’},‘安贞’,‘健翔桥’…}}

对应的url:http://bj.fangjia.com/ershoufang/–r-%E6%9C%9D%E9%98%B3%7Cw-5%E5%8F%B7%E7%BA%BF%7Cb-%E6%83%A0%E6%96%B0%E8%A5%BF%E8%A1%97

解码后的url:http://bj.fangjia.com/ershoufang/–r-朝阳|w-5号线|b-惠新西街

根据url的参数模式,可以有两种方式获取目的url:

  1. 根据索引路径获得目的url

在这里插入图片描述

# 获取房源信息列表(嵌套字典遍历)
def get_info_list(search_dict, layer, tmp_list, search_list):
    layer += 1  # 设置字典层级
    for i in range(len(search_dict)):
        tmp_key = list(search_dict.keys())[i]  # 提取当前字典层级key
        tmp_list.append(tmp_key)   # 将当前key值作为索引添加至tmp_list
        tmp_value = search_dict[tmp_key]
        if isinstance(tmp_value, str):   # 当键值为url时
            tmp_list.append(tmp_value)   # 将url添加至tmp_list
            search_list.append(copy.deepcopy(tmp_list))   # 将tmp_list索引url添加至search_list
            tmp_list = tmp_list[:layer]  # 根据层级保留索引
        elif tmp_value == '':   # 键值为空时跳过
            layer -= 2           # 跳出键值层级
            tmp_list = tmp_list[:layer]   # 根据层级保留索引
        else:
            get_info_list(tmp_value, layer, tmp_list, search_list)  # 当键值为列表时,迭代遍历
            tmp_list = tmp_list[:layer]
    return search_list
  1. 根据dict信息包装url

{‘朝阳’:{‘工体’:{‘5号线’}}}

参数:

——  r-朝阳

——  b-工体

——  w-5号线

组装参数:http://bj.fangjia.com/ershoufang/–r-朝阳|w-5号线|b-工体

# 根据参数创建组合url
def get_compose_url(compose_tmp_url, tag_args,  key_args):
    compose_tmp_url_list = [compose_tmp_url, '|' if tag_args != 'r-' else '', tag_args, parse.quote(key_args), ]
    compose_url = ''.join(compose_tmp_url_list)
    return compose_url

二、获取索引页最大页数

# 获取当前索引页面页数的url列表
def get_info_pn_list(search_list):
    fin_search_list = []
    for i in range(len(search_list)):
        print('>>>正在抓取%s' % search_list[i][:3])
        search_url = search_list[i][3]
        try:
            page = get_page(search_url)
        except:
            print('获取页面超时')
            continue
        soup = BS(page, 'lxml')
        # 获取最大页数
        pn_num = soup.select('span[class="mr5"]')[0].get_text()
        rule = re.compile(r'\d+')
        max_pn = int(rule.findall(pn_num)[1])
        # 组装url
        for pn in range(1, max_pn+1):
            print('************************正在抓取%s页************************' % pn)
            pn_rule = re.compile('[|]')
            fin_url = pn_rule.sub(r'|e-%s|' % pn, search_url, 1)
            tmp_url_list = copy.deepcopy(search_list[i][:3])
            tmp_url_list.append(fin_url)
            fin_search_list.append(tmp_url_list)
    return fin_search_list

三、抓取房源信息Tag

这是我们要抓取的Tag:

[‘区域’, ‘板块’, ‘地铁’, ‘标题’, ‘位置’, ‘平米’, ‘户型’, ‘楼层’, ‘总价’, ‘单位平米价格’]
在这里插入图片描述

# 获取tag信息
def get_info(fin_search_list, process_i):
    print('进程%s开始' % process_i)
    fin_info_list = []
    for i in range(len(fin_search_list)):
        url = fin_search_list[i][3]
        try:
            page = get_page(url)
        except:
            print('获取tag超时')
            continue
        soup = BS(page, 'lxml')
        title_list = soup.select('a[class="h_name"]')
        address_list = soup.select('span[class="address]')
        attr_list = soup.select('span[class="attribute"]')
        price_list = soup.find_all(attrs={"class": "xq_aprice xq_esf_width"})  # select对于某些属性值(属性值中间包含空格)无法识别,可以用find_all(attrs={})代替
        for num in range(20):
            tag_tmp_list = []
            try:
                title = title_list[num].attrs["title"]
                print(r'************************正在获取%s************************' % title)
                address = re.sub('\n', '', address_list[num].get_text())
                area = re.search('\d+[\u4E00-\u9FA5]{2}', attr_list[num].get_text()).group(0)
                layout = re.search('\d[^0-9]\d.', attr_list[num].get_text()).group(0)
                floor = re.search('\d/\d', attr_list[num].get_text()).group(0)
                price = re.search('\d+[\u4E00-\u9FA5]', price_list[num].get_text()).group(0)
                unit_price = re.search('\d+[\u4E00-\u9FA5]/.', price_list[num].get_text()).group(0)
                tag_tmp_list = copy.deepcopy(fin_search_list[i][:3])
                for tag in [title, address, area, layout, floor, price, unit_price]:
                    tag_tmp_list.append(tag)
                fin_info_list.append(tag_tmp_list)
            except:
                print('【抓取失败】')
                continue
    print('进程%s结束' % process_i)
    return fin_info_list

四、分配任务,并行抓取

对任务列表进行分片,设置进程池,并行抓取。

# 分配任务
def assignment_search_list(fin_search_list, project_num):  # project_num每个进程包含的任务数,数值越小,进程数越多
    assignment_list = []
    fin_search_list_len = len(fin_search_list)
    for i in range(0, fin_search_list_len, project_num):
        start = i
        end = i+project_num
        assignment_list.append(fin_search_list[start: end])  # 获取列表碎片
    return assignment_list

通过设置进程池并行抓取,时间缩短为单进程抓取时间的3/1,总计时间3h。

电脑为4核,经过测试,任务数为3时,在当前电脑运行效率最高。

五、将抓取结果存储到excel中,等待可视化数据化处理

# 存储抓取结果
def save_excel(fin_info_list, file_name):
    tag_name = ['区域', '板块', '地铁', '标题', '位置', '平米', '户型', '楼层', '总价', '单位平米价格']
    book = xlsxwriter.Workbook(r'C:\Users\Administrator\Desktop\%s.xls' % file_name)  # 默认存储在桌面上
    tmp = book.add_worksheet()
    row_num = len(fin_info_list)
    for i in range(1, row_num):
        if i == 1:
            tag_pos = 'A%s' % i
            tmp.write_row(tag_pos, tag_name)
        else:
            con_pos = 'A%s' % i
            content = fin_info_list[i-1]  # -1是因为被表格的表头所占
            tmp.write_row(con_pos, content)
    book.close()

在这里插入图片描述

总结:

当抓取数据规模越大,对程序逻辑要求就愈严谨,对python语法要求就越熟练。如何写出更加pythonic的语法,也需要不断学习掌握的。
请添加图片描述

↓ ↓ ↓ 加下方名片找我,直接拿源码还有案例 ↓ ↓ ↓

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/635115.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

go map源码探索(查找、插入、删除、扩容、遍历)

文章目录 概要一、Go map结构二、Go map初始化2.1、不带容量初始化2.2、带容量初始化 三、Go map查找四、Go map插入4.1、插入源码分析4.2、溢出桶申请策略 五、删除源码分析六、扩容与迁移源码分析6.1、扩容条件6.1.1、当前负载因子大于6.56.1.2、有过多的溢出桶 6.2、扩容6.3…

LVS+Keepalivedd

Keepalived 一、Keepalived及其工作原理二、实验非抢占模式的设置 三、脑裂现象四、Nginx高可用模式 一、Keepalived及其工作原理 keepalived是一个基于VRRP协议来实现的LVS服务高可用方案,可用解决静态路由出现的单点故障问题。 在一个LVS服务集群中通常有主服务器…

11.枚举和注解|Java学习笔记

文章目录 枚举 enumeration enum自定义实现枚举自定义类实现枚举总结 使用enum关键字实现枚举实现方法Enum类方法enum实现接口 注解注解的理解JDK的元Annotation(元注解) 枚举 enumeration enum 从一个需求引入: 要求创建季节(Season) 对象&…

matlab 使用预训练神经网络和SVM进行苹果分级(带图形界面)支持其他物品图片分级或者分类

目录 数据集: 实验代码:alexnet版 如果你的matlab不是正版,先看这里: 数据集结构: 训练代码: 训练结果: 图形界面: 界面展示: 其他: 输出结果: 实验…

代码规范

一 、代码规范 程序员写代码,不仅仅是实现功能 1. 名称 在Python开发过程中会创建文件夹/文件/变量等,这些在命名有一些潜规则(编写代码时也要注意pep8规范)。 文件夹,小写 & 小写下划线连接,例如&a…

jmeter 在linux服务器中执行性能测试、监听服务器资源指标

jmeter监控服务器资源 资源准备jmeter安装(Windows 版)jmeter安装(linux 版)ServerAgent安装(linux 版)配置脚本并执行测试 资源准备 下载apache-jmeter-5.5文件;下载ServerAgent-2.2.3文件; jmeter安装&…

ZooKeeper的集群部署和启动与关闭

ZooKeeper是一个分布式应用程序协调服务。一个ZooKeeper集群可以存在多个Follower和Observer服务器,但只允许存在一台Leader服务器。如果Leader服务器宕机,那么ZooKeeper集群的其它服务器会投票选举出一个新的Leader服务器,为防止投票数不过半…

2023最新社交圈子即时聊天通信小程序+前端UNIAPP

🎈 限时活动领体验会员:可下载程序网创项目短视频素材 🎈 🎉 有需要的朋友记得关赞评,阅读文章底部来交流!!! 🎉 ✨ 源码介绍 2023最新多端社交圈子系统源码 | 陌生人社交…

[openeuler]Yocto embedded 联合sig例会 (2022-12-15)

Yocto & embedded 联合sig例会 (2022-12-15)_哔哩哔哩_bilibili

【C/C++】详解 函数重载和应用

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞 关注支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; &#x1f525;c系列专栏&#xff1a;C/C零基础到精通 &#x1f525; 给大…

【零基础学JS - 11 】javaScript中的if..else表达式

&#x1f468;‍&#x1f4bb; 作者简介&#xff1a;程序员半夏 , 一名全栈程序员&#xff0c;擅长使用各种编程语言和框架&#xff0c;如JavaScript、React、Node.js、Java、Python、Django、MySQL等.专注于大前端与后端的硬核干货分享,同时是一个随缘更新的UP主. 你可以在各个…

[操作系统]4.文件管理

因为复习时间来不及了 还是老规矩,知识点覆盖不完全,具体内容请参考黑书,知识脉络来自王道操作系统 关于文件操作系统 1.文件系统基础 (1)文件的定义 文件时操作系统中的重要概念,是以计算机硬盘为基础载体存储在假期上的信息的集合 (2)文件的属性 文件的属性可以理解为文…

json-server 详解

这几天在写react的前端项目,想着后端接口没有,在网上也找不到比较合适的接口,所以在github和npm上翻了许久关于前端简单生成后端接口的工具,终于被找到了这个神仙工具json-server JSON-Server 是一个 Node 模块&#xff0c;运行 Express 服务器&#xff0c;你可以指定一个 jso…

CENTOS上的网络安全工具(二十四)Windows下的Hadoop+Spark编程环境构建

前面我们搭建了hadoop集群&#xff0c;spark集群&#xff0c;也利用容器构建了spark的编程环境。但是一般来说&#xff0c;就并行计算程序的开发&#xff0c;一刚开始一般是在单机上的&#xff0c;比如hadoop的single node。但是老师弄个容器或虚拟机用vscode远程访问式开发&am…

APM代码阅读(一):串口驱动

文章目录 前言一、AP_RangeFinder_TeraRanger_Serial.h二、AP_RangeFinder_TeraRanger_Serial.cpp三、AP_RangeFinder.cppinitdetect_instance_add_backendupdate 四、 AP_RangeFinder_Backend_Serial.cpp 前言 APM 4.2.3 以测距传感器的串口驱动为例进行阅读 其他的传感驱动都…

【Applied Algebra】扩域(Galois域)上的乘加法表构造

【Applied Algebra】扩域(Galois域)上的乘法表构造 在之前的文章里,我们讨论了扩域上(Galois域)的计算及其实现,但是侧重的是扩域中元素之间运算的细节实现,而如果想描述整个域的结构,就需要构造乘法表和加法表;实现仍然是基于c和符号计算库GiNaC; 运算表及其设计 考虑 F p n …

Zookeeper 基础知识汇总

一、zookeeper 概述 中文教程&#xff1a;https://www.docs4dev.com/docs/zh/zookeeper/r3.5.6/reference/zookeeperOver.html 1.1 概述 ZooKeeper 是⼀种分布式协调服务&#xff0c;⽤于管理⼤型主机。在分布式环境中协调和管理服务是 ⼀个复杂的过程。ZooKeeper 通过其简单的…

网内计算:可编程数据平面和技术特定应用综述

网内计算&#xff1a;可编程数据平面和技术特定应用综述 摘要——与云计算相比&#xff0c;边缘计算提供了更靠近终端设备的处理&#xff0c;降低了用户体验的延迟。最新的In-Network Computing范例采用可编程网络元素在数据达到边缘或云服务器之前计算&#xff0c;促进了常见…

Linux性能分析之perf(1)基础知识总结

Linux(09)之perf(1)基础知识总结 Author&#xff1a;Onceday Date&#xff1a;2023年1月31日 漫漫长路&#xff0c;才刚刚开始… 参考文档&#xff1a; Tutorial - Perf Wiki (kernel.org) linux性能分析工具专题-perf&#xff08;事件采样&#xff0c;全面性能分析&#x…

时钟树综合跑不下去,怎么破?

吾爱IC社区第二十一期IC训练营正式开始招募啦&#xff08;5月21号开营&#xff09;&#xff01;不知不觉小编的IC后端训练营课程已经举办21期了。每一期的报名时间也就1-3天&#xff0c;而且几乎每期都是爆满的情况。这背后的逻辑很简单。大家都信任吾爱IC社区这个品牌&#xf…