python抓取链家二手房数据

2023-10-30

#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import json
import openpyxl
import pandas as pd
import requests
from bs4 import BeautifulSoup
from openpyxl.utils.dataframe import dataframe_to_rows

session = requests.session()

# ========================= generate urls ==========================

def generate_home_url(city):  # 生成页面url
    return 'http://' + city + '.lianjia.com/ershoufang/'

def generate_area_page_url(page_count, city, path):  # 生成页面url
    url = 'http://' + city + '.lianjia.com' + path + 'pg{}/'
    for page_index in range(1, page_count):
        yield url.format(page_index)

# ========================= ==========================

def update_session():
    # 这里模拟一下请求头,头文件是从浏览器里面抓到的,否则服务会回复403错误,(其实就是服务器做的简单防爬虫检测)
    headers = {
        'Host': 'bj.lianjia.com',
        'Connection': 'keep-alive',
        'Upgrade-Insecure-Requests': '1',
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0',
        'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
        'Accept-Encoding': 'gzip, deflate, sdch, br',
        'Accept-Language': 'zh-CN,zh;q=0.8',
        'Cookie': 'TY_SESSION_ID=25a21767-af26-4543-b2b4-b92f7d6028b5; TY_SESSION_ID=f5cecba1-d783-4d40-b86d-72ee2accfccf; select_city=110000; lianjia_ssid=7ea6e0a0-dd03-48c2-9031-987bda2481c2; lianjia_uuid=435b41db-4268-4e59-9852-c4cd50e86646; sajssdk_2015_cross_new_user=1; sensorsdata2015jssdkcross=%7B%22distinct_id%22%3A%2216ff914d8d8522-08cf45a790e359-5e130c17-1024000-16ff914d8d9a86%22%2C%22%24device_id%22%3A%2216ff914d8d8522-08cf45a790e359-5e130c17-1024000-16ff914d8d9a86%22%2C%22props%22%3A%7B%22%24latest_traffic_source_type%22%3A%22%E7%9B%B4%E6%8E%A5%E6%B5%81%E9%87%8F%22%2C%22%24latest_referrer%22%3A%22%22%2C%22%24latest_referrer_host%22%3A%22%22%2C%22%24latest_search_keyword%22%3A%22%E6%9C%AA%E5%8F%96%E5%88%B0%E5%80%BC_%E7%9B%B4%E6%8E%A5%E6%89%93%E5%BC%80%22%7D%7D'
    }
    session.headers.clear()
    session.headers.update(headers)

def get_all_area_path(area_url):  # 分析url解析出区域的url
    update_session()
    res = session.get(area_url)

    if res.status_code == 200:
        soup = BeautifulSoup(res.text, 'lxml')

        urls = {}
        areas = soup.find_all('div', attrs={'data-role': 'ershoufang'})
        for item in areas:
            for a in item.find_all(name='a'):
                url = a.attrs['href']
                urls[a.text] = url
        # print('urls:'+str(urls))
        return urls

def get_all_page_urls(page_url):  # 分析url解析出每一页的详细url
    update_session()
    res = session.get(page_url)

    # res = requests.get(page_url, 'lxml')
    if res.status_code == 200:
        soup = BeautifulSoup(res.text, 'html.parser')

        urls = []
        infos = soup.find_all('div', attrs={'class': 'info clear'})
        for a in infos:
            url = a.a.attrs['href']
            urls.append(url)
        return urls

def get_page_by_url(page_url):  # 分析详细url获取所需信息
    print("get_page_by_url:" + page_url)
    update_session()
    try:
        res = session.get(page_url, timeout=(30, 120))

        # res = requests.get(page_url)
        if res.status_code == 200:
            info = {}
            soup = BeautifulSoup(res.text, 'lxml')
            info['标题'] = soup.select('.main')[0].text
            info['总价'] = soup.select('.total')[0].text + '万'
            info['每平方售价'] = soup.select('.unitPriceValue')[0].text
            info['参考总价'] = soup.select('.taxtext')[0].text
            info['建造时间'] = soup.select('.subInfo')[2].text
            info['小区名称'] = soup.select('.info')[0].text
            info['所在区域'] = soup.select('.info a')[0].text + ':' + soup.select('.info a')[1].text
            info['链家编号'] = str(page_url)[34:].rsplit('.html')[0]

            for ul in soup.find_all('div', attrs={'class': 'base'}):
                # print('ul:'+str(ul))
                for li in ul.find_all(name='li'):
                    # print('li:'+str(li.text))
                    span = li.find('span', attrs={'class': 'label'})
                    if '房屋户型' == span.text:
                        info['房屋户型'] = li.text.replace('房屋户型', '')
                    if '所在楼层' == span.text:
                        info['所在楼层'] = li.text.replace('所在楼层', '')
                    if '建筑面积' == span.text:
                        info['建筑面积'] = li.text.replace('建筑面积', '')
                    if '户型结构' == span.text:
                        info['户型结构'] = li.text.replace('户型结构', '')
                    if '套内面积' == span.text:
                        info['套内面积'] = li.text.replace('套内面积', '')
                    if '建筑类型' == span.text:
                        info['建筑类型'] = li.text.replace('建筑类型', '')
                    if '房屋朝向' == span.text:
                        info['房屋朝向'] = li.text.replace('房屋朝向', '')
                    if '建筑结构' == span.text:
                        info['建筑结构'] = li.text.replace('建筑结构', '')
                    if '装修情况' == span.text:
                        info['装修情况'] = li.text.replace('装修情况', '')
                    if '梯户比例' == span.text:
                        info['梯户比例'] = li.text.replace('梯户比例', '')
                    if '供暖方式' == span.text:
                        info['供暖方式'] = li.text.replace('供暖方式', '')
                    if '配备电梯' == span.text:
                        info['配备电梯'] = li.text.replace('配备电梯', '')
                    if '产权年限' == span.text:
                        info['产权年限'] = li.text.replace('产权年限', '')

            for ul in soup.find_all('div', attrs={'class': 'transaction'}):
                # print('ul:'+str(ul))
                for li in ul.find_all(name='li'):
                    # print('li:'+str(li.text))
                    span = li.find('span', attrs={'class': 'label'})
                    if '挂牌时间' == span.text:
                        info['挂牌时间'] = li.text.replace('挂牌时间', '').replace('\n', '').strip()
                    if '交易权属' == span.text:
                        info['交易权属'] = li.text.replace('交易权属', '').replace('\n', '').strip()
                    if '上次交易' == span.text:
                        info['上次交易'] = li.text.replace('上次交易', '').replace('\n', '').strip()
                    if '房屋用途' == span.text:
                        info['房屋用途'] = li.text.replace('房屋用途', '').replace('\n', '').strip()
                    if '房屋年限' == span.text:
                        info['房屋年限'] = li.text.replace('房屋年限', '').replace('\n', '').strip()
                    if ('产权所属' == span.text):
                        info['产权所属'] = li.text.replace('产权所属', '').replace('\n', '').strip()
                    if '抵押信息' == span.text:
                        info['抵押信息'] = li.text.replace('抵押信息', '').replace('\n', '').strip()
                    if '房本备件' == span.text:
                        info['房本备件'] = li.text.replace('房本备件', '').replace('\n', '').strip()
            # print("info:" + str(info))
            return info
    except Exception as e:
        print(str(e))
    return None

def do_write_workbook(ws, data):
    if data == None:
        return
    frame = pd.DataFrame(data, index=['0'])
    # print('frame:' + str(frame))
    for r in dataframe_to_rows(frame, index=False, header=True):
        if '标题' in str(r):
            continue
        #print('row:' + str(r))
        ws.append(r)

def create_sheet(workbook_file, wb, sheet_name):
    data = {'标题': '西四环,珠江峰景精装两居,正对小区花园,看房方便', '总价': '590万', '每平方售价': '57399元/平米',
            '参考总价': '首付及贷款情况请咨询经纪人', '建造时间': '2007年建/板塔结合', '小区名称': '珠江峰景',
            '所在区域': '丰台:岳各庄', '链家编号': '101106686239', '房屋户型': '房屋户型2室1厅1厨1卫',
            '所在楼层': '所在楼层高楼层 (共11层)', '建筑面积': '建筑面积102.79㎡', '户型结构': '户型结构平层',
            '套内面积': '套内面积84.24㎡', '建筑类型': '建筑类型板塔结合', '房屋朝向': '房屋朝向南',
            '建筑结构': '建筑结构钢混结构', '装修情况': '装修情况其他', '梯户比例': '梯户比例一梯四户',
            '供暖方式': '供暖方式集中供暖', '配备电梯': '配备电梯有', '产权年限': '产权年限70年',
            '挂牌时间': '2020-01-04', '交易权属': '商品房', '上次交易': '2008-07-07', '房屋用途': '普通住宅',
            '房屋年限': '满五年', '产权所属': '非共有', '抵押信息': '暂无数据', '房本备件': '已上传房本照片'}
    frame = pd.DataFrame(data, index=['0'])
    ws = wb.create_sheet(sheet_name)

    for r in dataframe_to_rows(frame, index=False, header=True):
        print('row:' + str(r))
        ws.append(r)
        # wb.save(workbook_file)
        break
    return ws

def has_sheet(wb, key):
    sheet_names = wb.get_sheet_names()
    for sheet_name in sheet_names:
        if key == sheet_name:
            return True
    return False

def fetch_all_area():
    city = 'bj'
    page_count = 15
    workbook_file = '链家二手房.xlsx'
    area_path_map = get_all_area_path(generate_home_url(city))
#这里要注意下,如果没有文件会失败,我没有新建操作.你可以建一个xlsx文件就行.
    wb = openpyxl.load_workbook(workbook_file)

    for key, val in area_path_map.items():
        print('key:' + str(key) + ' val:' + str(val))
        if has_sheet(wb, key): #由于抓取数据过程会失败,重新运行,所以有判断是否已经存在sheet.
            continue
        ws = create_sheet(workbook_file, wb, key)
        for area_url in generate_area_page_url(page_count, city, val):
            for page_url in get_all_page_urls(area_url):
                do_write_workbook(ws, get_page_by_url(page_url))
        wb.save(workbook_file)
        wb = openpyxl.load_workbook(workbook_file)

if __name__ == '__main__':
    fetch_all_area()

保存失败,不想再写了.直接上代码吧.

参考了 :https://blog.csdn.net/liujiayu2/article/details/86007384 的代码.

抓取的数据不太一样,是按区域存储sheet的,原文是直接分页抓取.打开链家二手房页面,会看到下面有小区/地铁,从这里的小区得到每一个小区的path,然后拼成url,再分页抓取数据.详情页的数据也把很多信息抓取了.像取暖,挂牌时间等.

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python抓取链家二手房数据 的相关文章

随机推荐

  • java:错误: 非法的表达式开始

    我写了这样一个代码 class Person private String name private int age Person System out println C name name age age Person String n
  • 记一道字节跳动的算法面试题

    来源公众号 苦逼的码农 作者 帅地 前几天有个朋友去面试字节跳动 面试官问了他一道链表相关的算法题 不过他一时之间没做出来 就来问了我一下 感觉这道题还不错 拿来讲一讲 题目 这其实是一道变形的链表反转题 大致描述如下 给定一个单链表的头节
  • CSAPP实验

    实验目的 1更好地熟悉和掌握计算机中整数和浮点数的二进制编码表示 2 实验中使用有限类型和数量的运算操作实现一组给定功能的函数 在此过程中加深对数据二进制编码表示的了解 3 熟悉linux基本操作命令 其中常用工具和程序开发环境 4 完善b
  • K8S安装部署的详细步骤与注意事项!

    目录 一 准备工作 1 关闭delinux和防火墙 2 配置 etc hosts文件 3 配置主机间的免密通道 4 关闭交换分区 提升性能 5 修改机器内核参数 6 配置阿里云repo源 7 配置时间同步 二 安装docker服务 1 安装
  • 百度网盘的最新插件(懂得都懂)

    下面先给大家介绍一下油猴插件 这个插件为什么叫油猴 现在我们经常提到的油猴插件 常指Tampermonkey 但Tampermonkey翻译过来是叫篡改猴 为什么会叫油猴呢 原因是因为另一个插件Greasemonkey 它翻译过来叫油猴 而
  • 010 Editor:二进制文件编辑利器

    使用010 Editor编辑二进制文件非常简单 只需打开目标文件即可 你可以使用导航面板轻松浏览文件内容 并直接在十六进制编辑器中进行编辑 010 Editor还提供了强大的模板功能 通过自定义模板 可以轻松解析二进制文件中的各种数据结构
  • 线程池任务队列和拒绝策略

    1 任务队列 BlockingQueue
  • SRTM1 V3.0数据批量下载

    USGS官网 EarthExplorer usgs gov 一 选取下载区域 可通过加载自己已有的shp文件选取 shp折点数属不能超过500 二 选取数据集 三 添加到Bulk Download 这里可选多页 然后点击 View Item
  • 按键点亮led灯

    原理图 K0这个按键按下时 开发板D1这个灯亮 松开 灯灭 代码如下 include stm32f4xx h void LED Init void 1 定义一个GPIO外设的结构体变量 GPIO InitTypeDef GPIO InitS
  • AHUT周赛2

    1 A Mahmoud and Ehab and the MEX Problem A Codeforces 核心在于x之前的数肯定是有的 x是没有的 所以从0开始一直到x 如果哪个数没有就加上哪个数 操作数 1 如果有x就删去x 操作数 1
  • 使用git将已有工程上传/push至Github完整初级过程

    相关链接 Github配置SSH基于Git Bash 设置Git的Username和Email 处理Key is invalid问题 如何在Eclipse平台使用git从GitHub上下载文件至本地及管理本地git项目 安装git Git下
  • Pandas库入门仅需10分钟

    数据处理的时候经常性需要整理出表格 在这里介绍pandas常见使用 目录如下 数据结构 导入导出文件 对数据进行操作 增加数据 创建数据 删除数据 改动数据 查找数据 常用操作 转置 常用统计值 参考链接 10 minutes to pan
  • 虚拟机存储IO的那点事

    随机IO vs 顺序IO 一般90 以上的虚拟机都是随机IO模型 用户交互类应用 如桌面 Web 它们的存储IO在Hypervisor看来都是随机的 这主要是因为我们常见的文件格式如jpg png exe elf一般都采用了元数据 数据的模
  • 乐高ev3python教程_入门篇丨使用EV3机器人,趣味学习Python编程语言~

    如 批判性思维 沟通和协作能力 使用EV3机器人趣味学习Python编程语言 让孩子们掌握计算思维 或许是一个不错的选择 什么是计算思维 计算思维这一概念 最先由Seymour Papert提出 后由周以真教授 Jeannette Wing
  • Microsoft Visual C++ 14.0 is required 的解决方案

    Pytho安装module时 可能会出现 error Microsoft Visual C 14 0 is required Get it with Microsoft Visual C Build Tools 这样的错误 对于此类问题 提
  • Spring学习(1)之IoC和Di

    文章目录 1 Spring 1 1简介 1 2优点与缺点 1 3组成 1 4提前知识 2 IoC的本质 2 1IoC创建对象的方式 3 Spring中xml文件中的属性的配置 3 1别名 3 2Bean的配置 3 3import 3 4be
  • Sequelizejs框架学习(待更新)

    model 如果你不想使用sql语句 那么你需要建立模型 model可以方便数据校验 数据关联等 可以用一下快捷命令创建model sequelize auto h ip d 库名 u 用户名 x 密码 p 端口号 o 生成模型的路径 t
  • 硬件虚拟化技术浅析

    目录 1 硬件虚拟化技术背景 2 KVM的内部实现概述 2 1 KVM的抽象对象 2 2 KVM的vcpu 2 3 KVM的IO虚拟化 2 3 1 IO的虚拟化 2 3 2 VirtIO 3 KVM IO可能优化地方 3 1 Virt IO
  • Google推荐的图片加载库Glide介绍

    英文原文 Introduction to Glide Image Loader Library for Android recommended by Google 首发地址 http jcodecraeer com a anzhuokaif
  • python抓取链家二手房数据

    usr bin env python3 coding utf 8 import json import openpyxl import pandas as pd import requests from bs4 import Beautif