Python爬取链家数据

技术:requests、BeautifulSoup、SQLite
解析页面,存数据到SQLite数据库,到时候你用navicat导出成csv什么的就行

1、确定城市

以天津为例,网页是https://tj.lianjia.com/ershoufang/rs/
在这里插入图片描述
把上面这些地区名字复制

2、爬取数据内容

在这里插入图片描述
在这里插入图片描述
从上面的属性中选择性爬取

3、给爷爬

3.1、创建中文映射

KEYMAP = {"房屋户型": "room_num","所在楼层": "floor_location","户型结构": "layout_structure","建筑类型": "building_type","房屋朝向": "house_orientation","建筑结构": "structure_type","装修情况": "decoration_condition","配备电梯": "equipped_elevator","交易权属": "transaction_ownership","房屋用途": "house_usage"
}
CITY_MAP = {"天津": "tj","北京": "bj"
}
DISTRICT_MAP = {"tj": {"和平": "heping", "南开": "nankai", "河西": "hexi", "河北": "hebei", "河东": "hedong", "红桥": "hongqiao", "西青": "xiqing","北辰": "beichen", "东丽": "dongli", "津南": "jinnan", "武清": "wuqing", "滨海新区": "binhaixinqu", "宝坻": "baodi", "蓟州": "jizhou","静海": "jinghai", "宁河": "ninghe"},"bj": {}
}

3.2、创建数据库

在项目目录下创建House.db文件,建表

import sqlite3# 根据上面的映射创建表,设置字段名
CREATE_SQL = ('CREATE TABLE House (''hid INTEGER PRIMARY KEY, ''rid INTEGER, ''title TEXT, ''area REAL, ''total_price INT, ''price INT, ''room_num INT, ''resblock_name TEXT, ''city_name TEXT, ''longitude REAL, ''latitude REAL, ''image TEXT, ''floor_location TEXT, ''layout_structure TEXT, ''building_type TEXT, ''house_orientation TEXT, ''structure_type TEXT, ''decoration_condition TEXT, ''equipped_elevator TEXT, ''transaction_ownership TEXT, ''house_usage TEXT );')
def create_table():cursor = conn.cursor()try:cursor.execute(CREATE_SQL)print("创建数据表")except:print('数据表已存在')cursor.close()conn = sqlite3.connect('House.db')
create_table()

3.3、多线程爬

虽然Python用多线程好像实际还是单线程,我也搞不清楚,但感觉至少有点用处。
注意多线程操作SQLite的时候,每个线程都要自己创建connection,不能共用同一个conn

3.4、爬数据

步骤如下:

  1. 分页爬列表,设置城市、地区、起始页码,如(‘天津’,‘南开’,1),访问网页https://{city}.lianjia.com/ershoufang/{district}/pg{page}。解析出网页元素中的房屋列表,获取一会爬房屋详细信息需要用的hid(房屋Id)和rid(小区id?不知道)
  2. 遍历列表中每一个房子,访问网页https://{city}.lianjia.com/ershoufang/{hid}.html,解析网页元素获取对应数据
  3. 存数据库,由于链家搜索应该加了一些推荐算法,之前爬过的房子你在下一页有可能还会看见他,所以存数据的时候,可以insert_or_update;或者只插入,若数据库中已经存在该房屋就不管他了,跳到下一次循环

其中,第二步爬每个房子的信息的时候可以多线程爬
第一步设置起始页码后,他会从起始页开始,循环爬后面的页,直到没数据了
懒得写了,直接贴全部代码了

import re
import threadingimport requests
import time
import json
import sqlite3
import math
from bs4 import BeautifulSoup
import concurrent.futures
import queueCREATE_SQL = ('CREATE TABLE House (''hid INTEGER PRIMARY KEY, ''rid INTEGER, ''title TEXT, ''area REAL, ''total_price INT, ''price INT, ''room_num INT, ''resblock_name TEXT, ''city_name TEXT, ''longitude REAL, ''latitude REAL, ''image TEXT, ''floor_location TEXT, ''layout_structure TEXT, ''building_type TEXT, ''house_orientation TEXT, ''structure_type TEXT, ''decoration_condition TEXT, ''equipped_elevator TEXT, ''transaction_ownership TEXT, ''house_usage TEXT );')
KEYMAP = {"房屋户型": "room_num","所在楼层": "floor_location","户型结构": "layout_structure","建筑类型": "building_type","房屋朝向": "house_orientation","建筑结构": "structure_type","装修情况": "decoration_condition","配备电梯": "equipped_elevator","交易权属": "transaction_ownership","房屋用途": "house_usage"
}
CITY_MAP = {"天津": "tj","北京": "bj"
}
DISTRICT_MAP = {"tj": {"和平": "heping", "南开": "nankai", "河西": "hexi", "河北": "hebei", "河东": "hedong", "红桥": "hongqiao", "西青": "xiqing","北辰": "beichen", "东丽": "dongli", "津南": "jinnan", "武清": "wuqing", "滨海新区": "binhaixinqu", "宝坻": "baodi", "蓟州": "jizhou","静海": "jinghai", "宁河": "ninghe"},"bj": {}
}def create_table():cursor = conn.cursor()try:cursor.execute(CREATE_SQL)print("创建数据表")except:print('数据表已存在')cursor.close()def crawl_house_list(city, district, start_page = 1):with concurrent.futures.ThreadPoolExecutor(max_workers=20) as executor:city = CITY_MAP[city]district_name = districtdistrict = DISTRICT_MAP[city][district_name]total_page = start_pagecurrent_page = start_pagetasks = [] # 线程提交任务while current_page <= total_page:list, total_page = get_house_list(city, district, current_page)print(f"{city}-{district}{current_page}/{total_page}】 num:{len(list)}")for item in list:# 没有记录才插入记录if not check_exist(conn, 'House', 'hid', item["hid"]):tasks.append(executor.submit(save_house_data, city, item, district_name))'''根据hid更新或插入数据house_data = get_house_data(city, item["hid"], item["rid"])if house_data:house_data["district_name"] = district_nameupdate_or_insert_data(conn, 'House', 'hid', house_data)else:print("查询{}出错".format(item))'''# 阻塞执行for future in concurrent.futures.as_completed(tasks):future.result()tasks = [] # 清空多线程任务列表current_page += 1# time.sleep(2)def get_house_list(city, district, page):url = f"https://{city}.lianjia.com/ershoufang/{district}/pg{page}"response = requests.get(url)list = []total_page = 0if response.status_code == 200:soup = BeautifulSoup(response.text, 'html.parser')# 获取房子列表ul = soup.find('ul', class_='sellListContent')if ul:li_list = ul.find_all('li')for li in li_list:rid = li.get('data-lj_action_resblock_id')hid = li.get('data-lj_action_housedel_id')list.append({"rid": rid, "hid": hid})else:print("Unable to find ul with class 'sellListContent'")# 获取总页数page_box = soup.find('div', class_='page-box house-lst-page-box')if page_box:page_data = page_box.get('page-data')if page_data:page_data_dict = json.loads(page_data)total_page = int(page_data_dict.get('totalPage'))else:print("No page data attribute found in page-box")else:print("Unable to find div with class 'page-box house-lst-page-box'")else:print("Failed to fetch the webpage")return list, total_pagedef get_house_data(city, hid, rid):url = f"https://{city}.lianjia.com/ershoufang/{hid}.html"response = requests.get(url)if response.status_code == 200:soup = BeautifulSoup(response.text, 'html.parser')house = {"hid": hid, "rid": rid}# 获取房屋信息、小区信息与经纬度script_tags = soup.find_all('script')for script in script_tags:if 'ershoufang/sellDetail/detailV3' in script.text:# 使用正则表达式匹配初始化数据对象match = re.search(r'init\(({.*?})\);', script.text, re.DOTALL)if match:try:data_str = match.group(1)data_str = re.sub(r"\$\.getQuery\(location\.href, '.*?'\)", '1', data_str)  # 去掉jquery代码data_str = re.sub(r"'", '"', data_str)  # 替换单引号为双引号data_str = re.sub(r'(\w+):([^/\\])', r'"\1":\2', data_str)  # 将key用双引号包裹data_str = re.sub(r"(\"isNewHouseReport\": \".*?\"),", r"\1", data_str)data_dict = json.loads(data_str)house["title"] = data_dict["title"]house["area"] = float(data_dict.get("area"))house["total_price"] = int(data_dict.get("totalPrice"))house["price"] = int(data_dict.get("price"))house["resblock_name"] = data_dict.get("resblockName")  # 小区名称house["city_name"] = data_dict.get("cityName")position = data_dict.get("resblockPosition").split(",")house["longitude"] = position[0]house["latitude"] = position[1]images = data_dict.get("images")if len(images) != 0:house["image"] = images[0]["url"]breakexcept:#print("错误:{}".format(data_str))return Noneelse:print("No script containing the desired data found")# 获取额外信息intro = soup.find('div', class_="introContent")if intro:# 基础信息base = intro.find('div', class_="base")lis = base.find_all('li')for li in lis:label_tag = li.find('span', class_='label')value = label_tag.next_sibling.strip()label_tag = label_tag.textif label_tag == "房屋户型":value = int(re.sub("(\d)室.*", r"\1", value))elif label_tag == "所在楼层":value = re.sub(r" ?\(.*?\)", "", value)if KEYMAP.get(label_tag):house[KEYMAP[label_tag]] = value# 交易信息transaction = intro.find('div', class_="transaction")lis = transaction.find_all('li')for li in lis:spans = li.find_all('span')label_tag = spans[0].textvalue = spans[1].textif KEYMAP.get(label_tag):house[KEYMAP[label_tag]] = valueelse:print("No intro block found")else:print("Failed to fetch the webpage")return Nonereturn housedef save_house_data(city, item, district_name):# 多线程每个都要有自己的connconn = sqlite3.connect('House.db')house_data = get_house_data(city, item["hid"], item["rid"])if house_data:house_data["district_name"] = district_nameinsert_data(conn, 'House', house_data)else:print("查询{}出错".format(item))def generate_update_query(table, data, key_column):update_query = f"UPDATE {table} SET "update_query += ", ".join(f"{key} = ?" for key in data.keys() if key != key_column)update_query += f" WHERE {key_column} = ?"return update_querydef generate_insert_query(table, data):insert_query = f"INSERT INTO {table} ({', '.join(data.keys())}) VALUES ({', '.join(['?'] * len(data))})"return insert_querydef update_or_insert_data(conn, table, key_column, data):cursor = conn.cursor()# 检查是否存在特定键值的数据key_value = data[key_column]cursor.execute(f"SELECT * FROM {table} WHERE {key_column} = ?", (key_value,))existing_data = cursor.fetchone()if existing_data:# 如果存在数据,则执行更新操作update_query = generate_update_query(table, data, key_column)values = []for key in data.keys():if key != key_column:values.append(data[key])values.append(key_value)cursor.execute(update_query, values)conn.commit()print("Data updated successfully.")else:# 如果不存在数据,则执行插入操作insert_query = generate_insert_query(table, data)cursor.execute(insert_query, list(data.values()))conn.commit()#print("Data inserted successfully.")cursor.close()def check_exist(conn, table, key_column, key_value):cursor = conn.cursor()# 检查是否存在特定键值的数据cursor.execute(f"SELECT * FROM {table} WHERE {key_column} = ?", (key_value,))existing_data = cursor.fetchone()return existing_data is not Nonedef insert_data(conn, table, data):cursor = conn.cursor()insert_query = generate_insert_query(table, data)cursor.execute(insert_query, list(data.values()))conn.commit()#print("Data inserted successfully.")cursor.close()conn = sqlite3.connect('House.db')
if __name__ == '__main__':# print(CREATE_SQL)create_table()districts = ['武清','滨海新区','宝坻','蓟州','静海','宁河'] # 设置你城市中想爬的地区for district in districts:print("=== Crawling " + district + " ===")crawl_house_list('天津', district, 1)

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

题目 2694: 蓝桥杯2022年第十三届决赛真题-最大数字【暴力解法】

最大数字 原题链接 &#x1f970;提交结果 思路 对于每一位&#xff0c;我我们都要尽力到达 9 所以我们去遍历每一位, 如果是 9 直接跳过这一位 如果可以上调到 9 我们将这一位上调到 9 &#xff0c;并且在a 中减去对应的次数 同样的&#xff0c;如果可以下调到 9&#xff0c;我…

MongoDB的安装和使用

1.MongoDB 安装 1.1 基于Docker安装 docker run --restartalways -d --name mongo -v /opt/mongodb/data:/data/db -p 27017:27017 mongo:4.0.6 1.2 客户端工具使用 MongoDB Compass | MongoDB 2.MongoDB 使用 2.1 引用依赖包 <dependency><groupId>org.sprin…

YOLOV5 分类:利用yolov5进行图像分类

1、前言 之前介绍了yolov5的目标检测示例,这次将介绍yolov5的分类展示 目标检测:YOLOv5 项目:训练代码和参数详细介绍(train)_yolov5训练代码的详解-CSDN博客 yolov5和其他网络的性能对比 yolov5分类的代码部分在这 2、数据集准备 yolov5分类的数据集就是常规的摆放方式…

TypeScript 中文错误消息

TypeScript 本身支持多语言显示错误消息&#xff0c;默认会追随操作系统或开发工具选择一个显示错误消息的语言。如果我们想强制让其显示某种语言可以如下设置&#xff0c;例如强制显示中文 命令行输入如下 npx tsc --locale zh-CN 对于 vsCode 中的错误消息可如下设置 设置…

[C++][算法基础]模拟散列表(哈希表)

维护一个集合&#xff0c;支持如下几种操作&#xff1a; I x&#xff0c;插入一个整数 x&#xff1b;Q x&#xff0c;询问整数 x 是否在集合中出现过&#xff1b; 现在要进行 N 次操作&#xff0c;对于每个询问操作输出对应的结果。 输入格式 第一行包含整数 N&#xff0c;…

macU盘在电脑上读不出来 u盘mac读不出来怎么办 macu盘不能写入 Tuxera NTFS for Mac免费下载

对于Mac用户来说&#xff0c;使用U盘是很常见的操作&#xff0c;但有时候可能会遇到Mac电脑无法读取U盘的情况&#xff0c;这时候就需要使用一些特定的工具软件来帮助我们解决问题。本文就来告诉大家macU盘在电脑上读不出来是怎么回事&#xff0c;u盘mac读不出来怎么办。 一、m…

结构型模式--2.桥接模式【大海贼时代】

1. 组建海贼团 哥尔D罗杰是罗杰海贼团船长。他最终征服了伟大航路&#xff0c;完成了伟大航路的航行&#xff0c;被人们成为海贼王。后来得了绝症&#xff0c;得知自己命不久矣&#xff0c;主动自首并在东海罗格镇被处刑。临死前罗杰的一句话“想要我的宝藏吗&#xff1f;想要…

期货量化交易软件:MQL5 中的范畴论 (第 15 部分)函子与图论

概述 在上一篇文章中&#xff0c;我们目睹了前期文章中涵盖的概念&#xff08;如线性序&#xff09;如何视作范畴&#xff0c;以及为什么它们的“态射”在与其它范畴相关时即构成函子。在本文中&#xff0c;我们赫兹量化软件将阐述来自前期文章中的概括&#xff0c;即通过查看…

【示例】MySQL-SQL语句优化

前言 本文主要讲述不同SQL语句的优化策略。 SQL | DML语句 insert语句 插入数据的时候&#xff0c;改为批量插入 插入数据的时候&#xff0c;按照主键顺序插入 大批量插入数据的时候&#xff08;百万&#xff09;&#xff0c;用load指令&#xff0c;从本地文件载入&#x…

实现鼠标在页面点击出现焦点及大十字星

近段时间&#xff0c;在完成项目进度情况显示时候&#xff0c;用户在操作鼠标时候&#xff0c;显示当鼠标所在位置对应时间如下图所示 代码实现步骤如下&#xff1a; 1.首先引用 jquery.1.7.js 2.再次引用raphael.js 3.然后引用graphics.js 4.最后引用mfocus.js 其中mfocu…

【UE Niagara】让粒子发出声音

步骤 首先新建一个Niagara发射器&#xff0c;使用Empty模板。打开后先添加一个“Spawn Burst Instantaneous”模块&#xff0c;设置发射数量为3 可以添加一个“Shape Location”使得每个粒子的初始位置不同 添加一个“Play Audio”模块&#xff0c;然后设置一个播放的音效 对N…

一个比 Celery 轻量好用的异步任务工具

文章目录 1、RQ安装2、RQ基本概念2.1、Queue2.2、Job2.3、Worker 3、RQ 高级用法3.1、自定义任务失败处理3.2、任务依赖关系3.3、定时任务 4、RQ web 界面5、查看任务结果6、RQ 与 celery 对比7、总结 Python RQ&#xff08;Redis Queue&#xff09;是一个轻量级的异步任务队列…

电脑文件名乱码,数据恢复有高招!

在日常使用电脑的过程中&#xff0c;突然遭遇文件名乱码的情况&#xff0c;确实让人头疼不已。原本井井有条的文件目录&#xff0c;一下子变得杂乱无章&#xff0c;文件名变成了一堆无意义的乱码字符。这种情况不仅影响了文件的正常使用&#xff0c;还可能导致重要数据的丢失。…

当努力成为日常,你准备好“戒瘾”了吗

不知道从什么时候开始&#xff0c;我们的朋友圈里充斥着各种“努力打卡”、“奋斗不息”的标语。大家仿佛一夜之间都变成了“卷王”&#xff0c;不是在努力就是在努力的路上…… 卷王争霸 努力成瘾的序幕 在每个看似充满正能量的背后&#xff0c;却隐藏着一个不容忽视的现象—…

java快速构建飞书API消息推送、消息加急等功能

文章目录 飞书机器人自定义机器人自定义应用机器人 自定义应用发送消息普通文本 text富文本 post图片 image文件 file语音 audio视频 media消息卡片 interactive分享群名片 share_chat分享个人名片 share_user 批量发送消息消息加急发送应用内加急发送短信加急 发送电话加急spr…

论文复现:nn.L1Loss()

nn.L1Loss() 是 PyTorch 中的一个损失函数&#xff0c;属于 torch.nn 模块的一部分。它计算预测值和真实值之间差的绝对值的平均值&#xff0c;也就是 L1 距离&#xff08;或曼哈顿距离&#xff09;。这个损失函数常用于回归任务&#xff0c;特别是当你希望减少异常值对总体损失…

核心api实操-Activiti7从入门到专家(5)

背景 上一节已经搭建了&#xff0c;具体的开发环境&#xff0c;数据库&#xff0c;并且找了一个可以用bpmnjs流程设计器&#xff0c;这一些&#xff0c;我们对核心api做个基础的实操&#xff0c;有个感性的认知&#xff0c;另外对数据库和基本数据流动有个理解。 部署 模板部…

深度学习pytorch实战第P2周:CIFAR10彩色图片识别

>- **&#x1f368; 本文为[&#x1f517;365天深度学习训练营](https://mp.weixin.qq.com/s/0dvHCaOoFnW8SCp3JpzKxg) 中的学习记录博客** >- **&#x1f356; 原作者&#xff1a;[K同学啊](https://mtyjkh.blog.csdn.net/)** 零、引言&#xff08;温故而知新&#xff…

智能合约平台开发指南

随着区块链技术的普及&#xff0c;智能合约平台已经成为了这个领域的一个重要趋势。智能合约可以自动化执行合同条款&#xff0c;大大减少了执行和监督合同条款所需的成本和时间。那么&#xff0c;如何开发一个智能合约平台呢&#xff1f;以下是一些关键步骤。 一、选择合适的区…

MySQL学习笔记2——基础操作

基础操作 一、增删改查1、添加数据2、删除数据3、修改数据4、查询语句 二、主键三、外键和连接1、外键2、连接 一、增删改查 1、添加数据 INSERT INTO 表名[(字段名[,字段名]…)] VALUES (值的列表); --[]表示里面的内容可选添加数据分为插入数据记录和插入查询结果 插入数据…