爬取西安二手房数据(多线程版)

本文介绍了一个使用Python爬虫技术抓取指定网站二手房房源信息的项目,通过多线程和Parsel库解析数据,存储至CSV和MySQL。文章还探讨了项目优化方向,如提高效率的异步方法和改进的存储选项。
摘要由CSDN通过智能技术生成

目录

项目背景

项目使用的技术栈与环境

所用技术:

平台和环境:

项目功能

项目的具体实现

项目的前期准备:

具体代码部分

首先创建一个HouseSpider类

Clear_data()函数:用于处理格式问题

get_house_data()函数:用于获取房屋的具体信息

Main():程序的主入口

项目结果展示

项目的不足


项目背景

目前房源数据作为人们都经常讨论的话题,房源数据又分为新房和二手房,而二手房想对于新房来说,不管是价格还是其他方面,对于居住地不稳定的打工来来说都是一个不错的选择。那么房源数据如何去获取呢,怎样才能得到自己想要的二手房房源信息呢?

这时候我们就会使用一些办法来获取这些房源数据,比如本项目所用到的python爬虫技术就可以快速的获取到自己想要的房源数据。

项目使用的技术栈与环境

所用技术:

  1. Python(作为该项目实现的编程语言)
  2. Python.requests(主要用于获取网页中的文本信息)
  3. Threading(线程——为了加快爬取速率所使用的一种方法)
  4. Parsel(用于对获取到的网页文本数据进行解析)

平台和环境:

  1. Windows11
  2. Pycharm3.8.10

项目功能

  1. 核心是实现对指定网页(https://xa.lianjia.com/ershoufang)数据进行爬取,并将数据按照指定的格式存储到csv中,方便用户对数据的保存和数据的查看。
  2. 本项目大致分为三个部分,数据的获取,数据解析和数据的存储,使用python自带的requests库对指定网页的文本数据进行获取;对获取的文本信息使用parsel库的一些方法进行文本解析得到所需要的数据;最后解析后的数据使用CSV文件格式和MYSQL进行存储。

项目的具体实现

  • 项目的前期准备:

  1. 首先进入指定的网址观察网页结构
  2. 网址首页页面

点击进入详情页

详情页中基本信息页面内容

首页和详情页之间的关联

        2. 选择所需要获取到的数据内容

需要获取所指定内容,比如首页中的关注人数和发布月份,还有详情页中的总价和单价以及小区的所在位置和基本信息的获取,这些都是需要获取的文本内容。

        3. 需要提前导入以下库,方便后期的函数调用和项目搭建

说明:csv用于处理CSV文件、threading用于多线程处理、datetime用于处理日期时间、ThreadPoolExecutor用于创建线程池、parsel用于解析网页内容、requests用于发送HTTP请求

前期工作已经准备就绪,下面开始具体操作部分

具体代码部分

  • 首先创建一个HouseSpider类

说明:

这是一个继承自Thread类的自定义线程类。在该类中定义了初始化方法__init__()、run()方法和一些辅助方法用于获取和处理房屋数据。

run()方法:在该方法中,使用ThreadPoolExecutor创建一个具有最大工作线程数为20的线程池,并调用get_house_data()方法来获取房屋数据。

  • Clear_data()函数:用于处理格式问题

说明:

replace:replace的作用是将字符串中的指定子串替换为新的子串。可以将指定的子串替换为新的子串,也可以指定替换次数。例如,如果要将字符串中的所有'a'替换为'b',可以使用replace函数:s.replace(′a′,′b′)

strip:strip的作用是去除字符串两端的指定字符(默认为空格)。可以指定要去除的字符,也可以不指定,默认情况下会去除空格。

  • get_house_data()函数:用于获取房屋的具体信息

def get_house_data(self, url):
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Safari/537.36 Edg/121.0.0.0'}
    try:
        response = requests.get(url=url, headers=headers)
        html_data = response.text

        selectors = parsel.Selector(html_data)
        href_list = selectors.css('.leftContent li .title a::attr(href)').getall()

        for href in href_list:
            href_res = requests.get(url=href, headers=headers)
            href_selector = parsel.Selector(href_res.text)
            #标题
            title = href_selector.css('.title .main::text').get()
            #总价
            totalPrice = href_selector.css('.price .total::text').get()
            #单价
            unitPrice = href_selector.css('.unitPriceValue::text').get()
            #关注人数和发布月份
            peopleNum = selectors.css('.info .followInfo ::text').get().split('/')
            guanzhurenshu = float(peopleNum[0].replace('人关注',''))
            fabushijian = float(peopleNum[1].replace('个月以前发布',''))
            # print(guanzhurenshu,fabushijian)
            if fabushijian==1:
                fabushijian = '0-30'
            elif fabushijian > 1 and fabushijian <=3:
                fabushijian = '30-90'
            elif fabushijian > 3 and fabushijian <=6:
                fabushijian = '90-180'
            elif fabushijian > 6 and fabushijian <=9:
                fabushijian = '180-270'
            elif fabushijian > 9 and fabushijian <=12:
                fabushijian = '270-365'
            #小区名称
            communityName = href_selector.css('.aroundInfo .communityName a::text').get()
            #区名
            areaName = href_selector.css('.aroundInfo .areaName a::text').get()
            # base_shuxing = href_selector.css('.base .content li .label::text').getall()
            #基础属性内容
            li_shuxing = href_selector.css('.base .content li::text').getall()
            base_data = self.clear_data(li_shuxing)
            fangwuhuxing = base_data[0]
            suozailouceng = base_data[1]
            jianzhumianji = base_data[2]
            huxingjiegou = base_data[3]
            taoneimianji = base_data[4]
            jianzhuleixing = base_data[5]
            chaoxiang = base_data[6]
            jianzhujiegou = base_data[7]
            zhuangxiuqingkaung = base_data[8]
            tihu = base_data[9]
            gongnuan = base_data[10]
            peibeidianti = base_data[11]
            loucenggaodu = base_data[12]

            # jiaoyi_shuxing = href_selector.css('.transaction .content li span .label::text').getall()
            #交易属性内容
            juti_shuxing = href_selector.css('.transaction .content li span::text').getall()
            jiaoyi_data = self.clear_data(juti_shuxing)
            guapai_time = jiaoyi_data[1]
            jiaoyiquanshu = jiaoyi_data[3]
            shangcijiaoyi_time = jiaoyi_data[5]
            guapai_time_obj = datetime.strptime(guapai_time, "%Y-%m-%d")
            shangcijiaoyi_time_obj = datetime.strptime(shangcijiaoyi_time, "%Y-%m-%d")
            cha_time = (guapai_time_obj - shangcijiaoyi_time_obj).days
            yongtu = jiaoyi_data[7]
            nianxian = jiaoyi_data[9]
            chanquansuoshu = jiaoyi_data[11]
            diyaxinxi = jiaoyi_data[13]
            fangbentiaojian = jiaoyi_data[15]

            data = {
                "标题": title,
                "总价": totalPrice,
                "单价": unitPrice,
                "关注人数": guanzhurenshu,
                "发布时间": fabushijian,
                "小区名称": communityName,
                "区名": areaName,
                "挂牌时间": guapai_time,
                "上次交易": shangcijiaoyi_time,
                "时间差": cha_time,
                "交易权属": jiaoyiquanshu,
                "房屋用途": yongtu,
                "房屋年限": nianxian,
                "产权所属": chanquansuoshu,
                "抵押信息": diyaxinxi,
                "房本条件": fangbentiaojian,
                "房屋户型": fangwuhuxing,
                "所在楼层": suozailouceng,
                "建筑面积": jianzhumianji,
                '户型结构': huxingjiegou,
                '套内面积': taoneimianji,
                '建筑类型': jianzhuleixing,
                '房屋朝向': chaoxiang,
                '建筑结构': jianzhujiegou,
                '装修情况': zhuangxiuqingkaung,
                '梯户比例': tihu,
                "供暖方式": gongnuan,
                "配备电梯": peibeidianti,
                "楼层高度": loucenggaodu,
            }
            with self.lock:
                with open('二手房test.csv', mode='a', encoding='utf-8', newline='') as f:
                    csv_writer = csv.DictWriter(f, fieldnames=data.keys())
                    if f.tell() == 0:
                        csv_writer.writeheader()
                    csv_writer.writerow(data)
                    print(data)
    except requests.exceptions.RequestException as e:
        print(e)

说明:get_house_data()方法:该方法用于获取每个房屋的详细信息,包括房屋标题、总价、单价、关注人数、发布时间等,并将数据存储到一个字典中。最后,将数据写入CSV文件中。

  • 文件的存储

    with open('二手房test.csv', mode='a', encoding='utf-8', newline='') as f:
                        csv_writer = csv.DictWriter(f, fieldnames=data.keys())
                        if f.tell() == 0:
                            csv_writer.writeheader()
                        csv_writer.writerow(data)
                        print(data)

  1. 主函数入口
    def main():
        qu_list = ['beilin', 'weiyang', 'xinchengqu', 'baqiao', 'yanliang', 'changan', 'lianhu', 'yanta', 'lantian',
                   'huyiqu', 'zhouzhi', 'gaoling', 'xixianxinquxian']
        threads = []
        for qu in qu_list:
            urls = [f'https://xa.lianjia.com/ershoufang/pg{i}/'+qu for i in range(1, 3)]
            spider = HouseSpider(urls)
            spider.start()
            threads.append(spider)
        for thread in threads:
            thread.join()

说明:main()函数:主函数中定义了一个区域列表qu_list,包含了要爬取的各个区域。这里使用了循环遍历去访问网页中的多页内容(模仿人为的点击下一页操作),然后循环遍历每个区域,生成对应的URL列表,并创建HouseSpider实例来爬取数据。

  • Main():程序的主入口

  • 项目的靓点
  1. 多线程:在项目中使用了多线程的方式来提高爬取的效率,提升了文件运行的整体性能和响应速度;也从一方面是程序具有并发处理的能力。
  2. 线程锁:使得数据同步,从而避免了资源的冲突,一定程度上确保了数据的完整性,从而提高了程序的稳定性。
  3. 使用了try...except..:增加了程序运行的稳定性,提高了代码的容错性

项目结果展示

项目的不足

首先这个项目结构相对完整,但是还有需要改进的地方:

  1. 效率问题:这里只是用了多线程的方法去提升爬虫爬取速率,提高资源的利用率,是否还有其它方法也可以做到这一点,比如可以尝试去使用异步来完成同样的工作内容,这个有待去进行对比;
  2. 存储方式问题:这里作者使用的存储方式是使用csv文件格式进行存储的,是否可以添加其他的文件存储方式,比如MYSQL,HDFS等
  3. 变量命名问题:这里的命名方式是为了作者查看起来方便,所以才这样命名,正常情况下按照大小驼峰命名法去命名即可。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值