爬虫第六式:链家房源爬取

news/2024/7/19 11:53:53 标签: python, 爬虫

温馨提示:

爬虫玩得好,监狱进得早。数据玩得溜,牢饭吃个够。

《刑法》第 285 条,非法获取计算机信息系统数据罪。
       违反国家规定,侵入前款规定以外的计算机信息系统或者采用其他技术手段,获取该计算机信息系统中存储、处理或者传输的数据,或者对该计算机信息系统实施非法控制,情节严重的,处三年以下有期徒刑或者拘役,并处或者单处罚金;情节特别严重的,处三年以上七年以下有期徒刑,并处罚金。

正文:

确定是否为静态

python">	打开二手房页面 -> 查看网页源码 -> 搜索关键字

我们先看网页中的关键字都是什么:

在这里插入图片描述
然后我们去源代码中查看一下关键字是否存在:
在这里插入图片描述
可以看到关键字也是存在的,只不过,源代码有点乱,看不太好,反正关键字肯定是存在的

接下来我们写Xpath表达式:
xpath表达式
在这里插入图片描述
我们看到xpath写出来了,但是感觉不对吧,右边给出的数据是 120条,这肯定是不对,这个网页的数据是30条,显示出120,肯定是有其他的也包含了,我们只能让xpath匹配到具体到属性了:

在这里插入图片描述
我们这样写到具体的属性了,但是值匹配到了2个????这是为什么,如果有细心的人发现了li和每个li后面的属性是不对的,有的是 class=“clear LOGCLICKDATA” 有的是 class=“clear LOGVIEWDATA LOGCLICKDATA”,但是以往我要这样的话是不是就用或符号了  |  但是我想让大家看的是这样,我鼠标滚轮往下滚一段距离,大家再看截图的效果:
在这里插入图片描述
是不是所有的li的属性都变成了:class="clear LOGCLICKDATA",这样,这也就是我本篇文章想说的一个xpath的知识点:

重要:页面中xpath不能全信,一切以响应内容为主

重要:页面中xpath不能全信,一切以响应内容为主

重要:页面中xpath不能全信,一切以响应内容为主

也就是我们在写xpath表达式的时候,要以响应出来的内容为主,先没事滚动两下,看是否会变,在进行提取操作!!

xpath表达式

python">【1】基准xpath表达式(匹配每个房源信息节点列表)
    '此处滚动鼠标滑轮时,li节点的class属性值会发生变化,通过查看网页源码确定xpath表达式'
    //ul[@class="sellListContent"]/li[@class="clear LOGVIEWDATA LOGCLICKDATA"]

我们再看提取的需求,楼房的信息提取表达式:

python">【2】依次遍历后每个房源信息xpath表达式
   2.1)名称: .//div[@class="positionInfo"]/a[1]/text()
   2.2)地址: .//div[@class="positionInfo"]/a[2]/text()

在这里插入图片描述
这样我们把小区名称和地址就提取出来了,因为两个都是a标签,所以我们用到了中括号1、中括号2,来区别他们,因为我们要的每个下面的文本,所有我们保险旗舰,加了 /text()

下面就是又不一样了,所以我们从新在写xpath表达式:

python">2.3)户型+面积+方位+是否精装+楼层+年代+类型
       info_list: './/div[@class="houseInfo"]/text()' ->  [0].strip().split('|')
       a)户型: info_list[0]
       b)面积: info_list[1]
       c)方位: info_list[2]
       d)精装: info_list[3]
       e)楼层:info_list[4]
       f)年代: info_list[5]
       g)类型: info_list[6]

在这里插入图片描述

info_list: ‘.//div[@class=“houseInfo”]/text()’ -> [0].strip().split(’|’) 这句话,我们看其实他就是把 户型、面积、方位、是否精装、楼层、年代、类型,分开了,因为它网页就是一句话写的,我们使用split(’|’) 按照 | 分割,提取出我们要的一小部分一小部分的数据,方便我们看
户型、面积、方位、是否精装、楼层、年代、类型 分别对应列表里的0,1,2,3,4,5,6 所以我们使用列表数据的索引进行提取

再看总价和单价:

python">2.4)总价+单价
       a)总价: .//div[@class="totalPrice"]/span/text()
       b)单价: .//div[@class="unitPrice"]/span/text()

在这里插入图片描述
总价的数字和万字是分开的,我们也就不要了,心里知道反正全国各地的房价是万计数的嘛,对吧
单价正常提取就行

接下来我们写代码:

导入的包:

python">import requests
from lxml import etree
import time
import random
from fake_useragent import UserAgent

定义功能函数,减少重复代码

找到URL地址的规律:
https://bj.lianjia.com/ershoufang/pg1/ —— 第一页
https://bj.lianjia.com/ershoufang/pg2/ —— 第二页
https://bj.lianjia.com/ershoufang/pg3/ —— 第三页
… …

python">class LianjiaSpider(object):
    def __init__(self):
        self.url = 'https://bj.lianjia.com/ershoufang/pg{}/'

定义url请求函数

python">def parse_html(self,url):
    headers = {'User-Agent':UserAgent().random}
    html = requests.get(url=url,headers=headers).content.decode('utf-8','ignore')
    self.get_data(html)

定义爬虫功能请求函数

python">def get_data(self,html):
    p = etree.HTML(html)
    # 基准xpath: [<element li at xxx>,<element li>]
    # 得到每个房源信息的li节点对象列表,如果此处匹配出来空,则一定要查看响应内容
    li_list = p.xpath('//ul[@class="sellListContent"]/li[@class="clear LOGVIEWDATA LOGCLICKDATA"]')
    # for遍历,依次提取每个房源信息,放到字典item中
    item = {}
    for li in li_list:
        # 名称+区域
        name_list = li.xpath('.//div[@class="positionInfo"]/a[1]/text()')
        item['name'] = name_list[0].strip() if name_list else None
        address_list = li.xpath('.//div[@class="positionInfo"]/a[2]/text()')
        item['address'] = address_list[0].strip() if address_list else None
python"> # 户型+面积+方位+是否精装+楼层+年代+类型
 # h_list: ['']
 h_list = li.xpath('.//div[@class="houseInfo"]/text()')
 if h_list:
     info_list = h_list[0].split('|')
     if len(info_list) == 7:
         item['model'] = info_list[0].strip()
         item['area'] = info_list[1].strip()
         item['direct'] = info_list[2].strip()
         item['perfect'] = info_list[3].strip()
         item['floor'] = info_list[4].strip()
         item['year'] = info_list[5].strip()[:-2]
         item['type'] = info_list[6].strip()
     else:
         item['model'] = item['area'] = item['direct'] = item['perfect'] = item['floor'] = item['year'] = item['type'] = None
 else:
     item['model'] = item['area'] = item['direct'] = item['perfect'] = item['floor'] = item['year'] = item['type'] = None

这样写我们之前有提到过,是因为我们不确定是否所有我们提取的数据都是存在的,我们就先写出了简单的提取,默认他全有,然后我们 if、else判断一下,如果数据都有代码就执行if里面的,没有就执行else里面的,这样也就节省了我们代码量,最里层if语句是判断是不是执行到了户型+面积+方位+是否精装+楼层+年代+类型 这个板块,外面的是判断代码的数据是不是全有

下面是总价和单价的表达式: 我们同样做了为空判断

python"> # 总价+单价
 total_list = li.xpath('.//div[@class="totalPrice"]/span/text()')
 item['total'] = total_list[0].strip() if total_list else None
 unit_list = li.xpath('.//div[@class="unitPrice"]/span/text()')
 item['unit'] = unit_list[0].strip() if unit_list else None

最后程序入口函数,用来控制整体逻辑:

python"> def run(self):
 	 for pg in range(1,101):
         url = self.url.format(pg)
         self.parse_html(url)
         time.sleep(random.randint(1,2))

奉上全部代码:

python">import requests
from lxml import etree
import time
import random
from fake_useragent import UserAgent

class LianjiaSpider(object):
    def __init__(self):
        self.url = 'https://bj.lianjia.com/ershoufang/pg{}/'

    def parse_html(self,url):
        headers = {'User-Agent':UserAgent().random}
        html = requests.get(url=url,headers=headers).content.decode('utf-8','ignore')
        self.get_data(html)


    def get_data(self,html):
        p = etree.HTML(html)
        # 基准xpath: [<element li at xxx>,<element li>]
        li_list = p.xpath('//ul[@class="sellListContent"]/li[@class="clear LOGVIEWDATA LOGCLICKDATA"]')
        # for遍历,依次提取每个房源信息,放到字典item中
        item = {}
        for li in li_list:
            # 名称+区域
            name_list = li.xpath('.//div[@class="positionInfo"]/a[1]/text()')
            item['name'] = name_list[0].strip() if name_list else None
            address_list = li.xpath('.//div[@class="positionInfo"]/a[2]/text()')
            item['address'] = address_list[0].strip() if address_list else None
            # 户型+面积+方位+是否精装+楼层+年代+类型
            # h_list: ['']
            h_list = li.xpath('.//div[@class="houseInfo"]/text()')
            if h_list:
                info_list = h_list[0].split('|')
                if len(info_list) == 7:
                    item['model'] = info_list[0].strip()
                    item['area'] = info_list[1].strip()
                    item['direct'] = info_list[2].strip()
                    item['perfect'] = info_list[3].strip()
                    item['floor'] = info_list[4].strip()
                    item['year'] = info_list[5].strip()[:-2]
                    item['type'] = info_list[6].strip()
                else:
                    item['model'] = item['area'] = item['direct'] = item['perfect'] = item['floor'] = item['year'] = item['type'] = None
            else:
                item['model'] = item['area'] = item['direct'] = item['perfect'] = item['floor'] = item['year'] = item['type'] = None

            # 总价+单价
            total_list = li.xpath('.//div[@class="totalPrice"]/span/text()')
            item['total'] = total_list[0].strip() if total_list else None
            unit_list = li.xpath('.//div[@class="unitPrice"]/span/text()')
            item['unit'] = unit_list[0].strip() if unit_list else None

            print(item)

    def run(self):
        for pg in range(1,101):
            url = self.url.format(pg)
            self.parse_html(url)
            time.sleep(random.randint(1,2))

if __name__ == '__main__':
    spider = LianjiaSpider()
    spider.run()

运行:
在这里插入图片描述
在这里插入图片描述
ok,如果想保存起来可以用数据库存储起来,自己实现一下吧!!


http://www.niftyadmin.cn/n/835465.html

相关文章

[大赛推荐]短视频开发大赛,万元现金大奖等你来拿

要问时下什么最潮、最火&#xff1f;年轻人最爱玩儿&#xff1f;人机必备短视频 App15s 拍摄视频&#xff0c;记录生活人人都是美好生活的导演家酷炫、魔性、鬼畜短视频个个都是潮流前线的潜力股在这个全民短视频的年代&#xff0c;你&#xff0c;只甘心做一个看客吗&#xff1…

Go调试工具—— Delve

参考https://github.com/go-delve/delve 安装 首先你必须有等于或高于1.8版本的Go,我的版本是&#xff1a; userdeMBP:go-learning user$ go version go version go1.11.4 darwin/amd64 我是用的是Mac,所以使用的是OSX安装方法&#xff1a; 然后使用go get 进行安装&#xff1a…

爬虫小插曲:关于代理参数-proxies那些事

代理参数-proxies 定义及分类 【1】定义 : 代替你原来的IP地址去对接网络的IP地址【2】作用 : 隐藏自身真实IP,避免被封普通代理 【1】获取代理IP网站快代理、全网代理、代理精灵、... ...【2】参数类型proxies { 协议:协议://IP:端口号 }proxies {http:http://IP:端口号,ht…

4.36-域名重定向 4.37-用户认证 4.38-Nginx访问日志 4.39-日志不记录静态文件 4.40-日志切割...

2019独角兽企业重金招聘Python工程师标准>>> 4.36-域名重定向 配置第二个域名&#xff1a; vi /etc/nginx/conf.d/blog.aminglinux.cc.conf 在 server_name 那一行的域名后面再加一个域名&#xff0c;空格作为分隔。 nginx -t nginx -s reload域名重定向&#xff1a…

理解原型与原型链

原型与原型链是学习JavaScript这门语言不能不理解的两个重要概念&#xff0c;为什么&#xff1f;因为JavaScript是一门基于原型的语言。怎么理解“JavaScript是一门基于原型的语言”&#xff1f;在软件设计模式中&#xff0c;有一种模式叫做原型模式&#xff0c;JavaScript正是…

爬虫第七式:有道翻译破解案例(post)

温馨提示&#xff1a; 爬虫玩得好&#xff0c;监狱进得早。数据玩得溜&#xff0c;牢饭吃个够。 《刑法》第 285 条&#xff0c;非法获取计算机信息系统数据罪。 违反国家规定&#xff0c;侵入前款规定以外的计算机信息系统或者采用其他技术手段&#xff0c;获取该计算机…

人脸识别

计划 实现了一个基于 PCA 的人脸识别 方法 &#xff0c;我 称之为 “ 特征点方法 ”&#xff0c; 所有的功能简单而且实用 。下面&#xff0c;我使用一个简单的MATLAB脚本 说明 它的用法 。一般情况 &#xff0c; 你应该 按照以下这个顺序执行这个方法 &#xff1a;1. 选择实际…

系统SDK介绍-02

系统SDK介绍 打开相册选择图片打开相册选择视频打开相机拍摄图片打开相机拍摄视频配置权限&#xff1a; 在info.plist文件中添加需要的权限 相机权限&#xff1a;Privacy - Camera Usage Description 允许此权限才能使用相机功&#xff0c;这样才能录制视频&#xff0c;并且想要…