【Python_requests学习笔记(二)】基于requests和lxml模块,爬取链家房产数据

2024-01-23 08:40

本文主要是介绍【Python_requests学习笔记(二)】基于requests和lxml模块,爬取链家房产数据,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

基于requests和lxml模块,爬取链家房产数据

前言

此篇文章中介绍基于requests,lxml模块和Xpath选择器,爬取链家房产数据的案例。

正文

1、需求梳理

抓取链家二手房网站中的房源信息,如房源名称、地址、户型、面积、方位、是否精装、楼层、年代、类型、总价。

2、爬虫思路

  1. 确认所抓数据在响应内容中是否存在
    所抓取的内容在响应内容中存在在这里插入图片描述
  2. 分析url地址规律
    第一页:https://qd.lianjia.com/ershoufang/pg
    第二页:https://qd.lianjia.com/ershoufang/pg2/
    第三页:https://qd.lianjia.com/ershoufang/pg3/

    第N页:https://qd.lianjia.com/ershoufang/pgn/
    url地址:https://qd.lianjia.com/ershoufang/pg{n}/
  3. 写xpath表达式
    在这里插入图片描述
    从上图li标签中可以看到 检查中存在两个属性:
    clear LOGCLICKDATA
    clear LOGVIEWDATA LOGCLICKDATA
    所以需要通过检查网页源代码中查看,究竟以哪一个为准:
    在这里插入图片描述
    以此确定基准xpath://li[@class='clear LOGVIEWDATA LOGCLICKDATA']
    for循环依次遍历后得到详细信息:
    名称:.//div[@class='positionInfo']/a[1]/text()
    区域:.//div[@class='positionInfo']/a[2]/text()
    详细信息:.//div[@class='houseInfo']/text()
    总价:.//div[@class='totalPrice']/span/text()
    单价:.//div[@class='unitPrice']/span/text()
  4. 编写程序框架、完善程序

注意:

1、在写xpath表达式时一切以响应内容为主
2、页面HTML为最终渲染完之后的,和响应内容的HTML不一定相同
3、防止页面中出现特殊数据,所以在取下标索引前需要先进行判断
4、如果出现特殊页面迟迟不给响应,则设立重试机制

3、程序实现

  1. 初始化函数
    def __init__(self):self.url = 'https://qd.lianjia.com/ershoufang/pg{}/'  # url地址self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'}  # 重构请求头self.i = 0  # 初始化计数
  1. 获取响应内容函数
    def get_html(self, url):"""function:  获取响应内容函数in:  url:传入的url地址out:  Nonereturn:  int >0 okothers:  Get Response Content Function"""for i in range(3):  # 如果有异常,尝试三次# noinspection PyBroadExceptiontry:html = requests.get(url=url, headers=self.headers, timeout=3).text  # 设置3秒钟的超时时间self.parse_html(html)  # 调用 xpath提取数据函数self.i += 1  # 爬取成功,计数+1print("第{}页爬取成功!".format(self.i))  # 打印break  # 跳出except Exception as e:print("Retry......")  # 捕捉异常
  1. xpath提取数据函数
    def parse_html(self, html):"""function:  xpath提取数据函数in:  html:响应内容out:  Nonereturn:  Noneothers:  Extract Data By Xpath Function"""p = etree.HTML(html)  # 创造解析对象li_list = p.xpath("//li[@class='clear LOGVIEWDATA LOGCLICKDATA']")  # 解析对象调用xpathitem = {}  # 定义一个空字典for li in li_list:  # 遍历 解析对象调用xpath后 得到的数据name_list = li.xpath(".//div[@class='positionInfo']/a[1]/text()")item["名称"] = name_list[0].strip() if name_list else None  # 判断得到的名称列表是否为空address_list = li.xpath(".//div[@class='positionInfo']/a[2]/text()")item["地址"] = address_list[0].strip() if name_list else None  # 判断得到的地址列表是否为空info_li = li.xpath(".//div[@class='houseInfo']/text()")if info_li:  # 判断房源信息是否为空info_li = info_li[0].split("|")  # 用"|"分割if len(info_li) == 7:  # 长度=7item["户型"] = info_li[0].strip()item["面积"] = info_li[1].strip()item["朝向"] = info_li[2].strip()item["装修"] = info_li[3].strip()item["楼层"] = info_li[4].strip()item["年限"] = info_li[5].strip()item["种类"] = info_li[6].strip()else:if len(info_li) == 6:  # 长度=6item["户型"] = info_li[0].strip()item["面积"] = info_li[1].strip()item["朝向"] = info_li[2].strip()item["装修"] = info_li[3].strip()item["楼层"] = info_li[4].strip()item["种类"] = info_li[5].strip()else:if len(info_li) == 8:  # 长度=8item["户型"] = info_li[0].strip()item["面积"] = info_li[1].strip()item["朝向"] = info_li[2].strip()item["装修"] = info_li[3].strip()item["楼层"] = info_li[4].strip()item["年限"] = info_li[5].strip()item["种类"] = info_li[6].strip()item["种类"] += info_li[7].strip()else:item["户型"] = item["面积"] = item["朝向"] = item["装修"] = item["楼层"] = item["年限"] = item["种类"] = Noneelse:item["户型"] = item["面积"] = item["朝向"] = item["装修"] = item["楼层"] = item["年限"] = item["种类"] = Nonetotal_list = li.xpath(".//div[@class='totalPrice totalPrice2']/span/text()")item["总价"] = total_list[0].strip() if total_list else None  # 判断得到的总价列表是否为空unit_list = li.xpath(".//div[@class='unitPrice']/span/text()")item["单价"] = unit_list[0].strip() if unit_list else None  # 判断得到的单价列表是否为空print(item)  # 打印信息
  1. 程序入口函数
    def run(self):"""function:  程序入口函数in:  Noneout:  Nonereturn:  Noneothers:  Program Entry Function"""for pg in range(1, 6):  # 爬取1-5页url = self.url.format(pg)  # 拼接url地址self.get_html(url)  # 调用 获取响应内容函数time.sleep(random.randint(1, 2))  # 1-2s延时

4、完整代码

import time
import random
import requests
from lxml import etreeclass LianjiaSpider:"""链家二手房数据抓取"""def __init__(self):self.url = 'https://qd.lianjia.com/ershoufang/pg{}/'  # url地址self.headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'}  # 重构请求头self.i = 0  # 初始化计数def get_html(self, url):"""function:  获取响应内容函数in:  url:传入的url地址out:  Nonereturn:  int >0 okothers:  Get Response Content Function"""for i in range(3):  # 如果有异常,尝试三次# noinspection PyBroadExceptiontry:html = requests.get(url=url, headers=self.headers, timeout=3).text  # 设置3秒钟的超时时间self.parse_html(html)  # 调用 xpath提取数据函数self.i += 1  # 爬取成功,计数+1print("第{}页爬取成功!".format(self.i))  # 打印break  # 跳出except Exception as e:print("Retry......")  # 捕捉异常def parse_html(self, html):"""function:  xpath提取数据函数in:  html:响应内容out:  Nonereturn:  Noneothers:  Extract Data By Xpath Function"""p = etree.HTML(html)  # 创造解析对象li_list = p.xpath("//li[@class='clear LOGVIEWDATA LOGCLICKDATA']")  # 解析对象调用xpathitem = {}  # 定义一个空字典for li in li_list:  # 遍历 解析对象调用xpath后 得到的数据name_list = li.xpath(".//div[@class='positionInfo']/a[1]/text()")item["名称"] = name_list[0].strip() if name_list else None  # 判断得到的名称列表是否为空address_list = li.xpath(".//div[@class='positionInfo']/a[2]/text()")item["地址"] = address_list[0].strip() if name_list else None  # 判断得到的地址列表是否为空info_li = li.xpath(".//div[@class='houseInfo']/text()")if info_li:  # 判断房源信息是否为空info_li = info_li[0].split("|")  # 用"|"分割if len(info_li) == 7:  # 长度=7item["户型"] = info_li[0].strip()item["面积"] = info_li[1].strip()item["朝向"] = info_li[2].strip()item["装修"] = info_li[3].strip()item["楼层"] = info_li[4].strip()item["年限"] = info_li[5].strip()item["种类"] = info_li[6].strip()else:if len(info_li) == 6:  # 长度=6item["户型"] = info_li[0].strip()item["面积"] = info_li[1].strip()item["朝向"] = info_li[2].strip()item["装修"] = info_li[3].strip()item["楼层"] = info_li[4].strip()item["种类"] = info_li[5].strip()else:if len(info_li) == 8:  # 长度=8item["户型"] = info_li[0].strip()item["面积"] = info_li[1].strip()item["朝向"] = info_li[2].strip()item["装修"] = info_li[3].strip()item["楼层"] = info_li[4].strip()item["年限"] = info_li[5].strip()item["种类"] = info_li[6].strip()item["种类"] += info_li[7].strip()else:item["户型"] = item["面积"] = item["朝向"] = item["装修"] = item["楼层"] = item["年限"] = item["种类"] = Noneelse:item["户型"] = item["面积"] = item["朝向"] = item["装修"] = item["楼层"] = item["年限"] = item["种类"] = Nonetotal_list = li.xpath(".//div[@class='totalPrice totalPrice2']/span/text()")item["总价"] = total_list[0].strip() if total_list else None  # 判断得到的总价列表是否为空unit_list = li.xpath(".//div[@class='unitPrice']/span/text()")item["单价"] = unit_list[0].strip() if unit_list else None  # 判断得到的单价列表是否为空print(item)  # 打印信息def run(self):"""function:  程序入口函数in:  Noneout:  Nonereturn:  Noneothers:  Program Entry Function"""for pg in range(1, 6):  # 爬取1-5页url = self.url.format(pg)  # 拼接url地址self.get_html(url)  # 调用 获取响应内容函数time.sleep(random.randint(1, 2))  # 1-2s延时if __name__ == '__main__':spider = LianjiaSpider()  # 类实例化spider.run()  # 调用入口函数

5、实现效果

在这里插入图片描述

这篇关于【Python_requests学习笔记(二)】基于requests和lxml模块,爬取链家房产数据的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/635840

相关文章

VSCode配置Anaconda Python环境的实现

《VSCode配置AnacondaPython环境的实现》VisualStudioCode中可以使用Anaconda环境进行Python开发,本文主要介绍了VSCode配置AnacondaPytho... 目录前言一、安装 Visual Studio Code 和 Anaconda二、创建或激活 conda

pytorch+torchvision+python版本对应及环境安装

《pytorch+torchvision+python版本对应及环境安装》本文主要介绍了pytorch+torchvision+python版本对应及环境安装,安装过程中需要注意Numpy版本的降级,... 目录一、版本对应二、安装命令(pip)1. 版本2. 安装全过程3. 命令相关解释参考文章一、版本对

Java进阶学习之如何开启远程调式

《Java进阶学习之如何开启远程调式》Java开发中的远程调试是一项至关重要的技能,特别是在处理生产环境的问题或者协作开发时,:本文主要介绍Java进阶学习之如何开启远程调式的相关资料,需要的朋友... 目录概述Java远程调试的开启与底层原理开启Java远程调试底层原理JVM参数总结&nbsMbKKXJx

大数据spark3.5安装部署之local模式详解

《大数据spark3.5安装部署之local模式详解》本文介绍了如何在本地模式下安装和配置Spark,并展示了如何使用SparkShell进行基本的数据处理操作,同时,还介绍了如何通过Spark-su... 目录下载上传解压配置jdk解压配置环境变量启动查看交互操作命令行提交应用spark,一个数据处理框架

讯飞webapi语音识别接口调用示例代码(python)

《讯飞webapi语音识别接口调用示例代码(python)》:本文主要介绍如何使用Python3调用讯飞WebAPI语音识别接口,重点解决了在处理语音识别结果时判断是否为最后一帧的问题,通过运行代... 目录前言一、环境二、引入库三、代码实例四、运行结果五、总结前言基于python3 讯飞webAPI语音

基于Python开发PDF转PNG的可视化工具

《基于Python开发PDF转PNG的可视化工具》在数字文档处理领域,PDF到图像格式的转换是常见需求,本文介绍如何利用Python的PyMuPDF库和Tkinter框架开发一个带图形界面的PDF转P... 目录一、引言二、功能特性三、技术架构1. 技术栈组成2. 系统架构javascript设计3.效果图

通过ibd文件恢复MySql数据的操作方法

《通过ibd文件恢复MySql数据的操作方法》文章介绍通过.ibd文件恢复MySQL数据的过程,包括知道表结构和不知道表结构两种情况,对于知道表结构的情况,可以直接将.ibd文件复制到新的数据库目录并... 目录第一种情况:知道表结构第二种情况:不知道表结构总结今天干了一件大事,安装1Panel导致原来服务

Python如何在Word中生成多种不同类型的图表

《Python如何在Word中生成多种不同类型的图表》Word文档中插入图表不仅能直观呈现数据,还能提升文档的可读性和专业性,本文将介绍如何使用Python在Word文档中创建和自定义各种图表,需要的... 目录在Word中创建柱形图在Word中创建条形图在Word中创建折线图在Word中创建饼图在Word

Python Excel实现自动添加编号

《PythonExcel实现自动添加编号》这篇文章主要为大家详细介绍了如何使用Python在Excel中实现自动添加编号效果,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、背景介绍2、库的安装3、核心代码4、完整代码1、背景介绍简单的说,就是在Excel中有一列h=会有重复

Jmeter如何向数据库批量插入数据

《Jmeter如何向数据库批量插入数据》:本文主要介绍Jmeter如何向数据库批量插入数据方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录Jmeter向数据库批量插入数据Jmeter向mysql数据库中插入数据的入门操作接下来做一下各个元件的配置总结Jmete