爬虫实例(1):房价爬取

730 阅读4分钟

前言

  这系列的博客是我用来记录一些爬虫的小项目实例的,使用的抓包工具是request,数据解析工具是xpath,因为xpath相较于bs4和正则更加常用、便捷高效。下面就简单介绍一下xpath的原理和基本使用。

1 xpath原理

  首先是实例化一个etree的对象,且需要将被解析的页面源码加载到该对象中,这个页面源码可以已经下载在本地(etree.parse(filePath))也可以是从互联网上(etree.HTML('page_text'))获得的。其次调用etree对象中的方法结合xpath表达式实现标签的定位和内容的捕获。

2 xpath表达式

"/" :最左侧的斜杆表示从根节点开始遍历。处于中间位置表示一个层级。 "//":表示多个层级。相当于bs4中的">>"。 标签定位://div[@class="属性名"],要注意的是标签索引定位是从1开始。 取文本:/text()获取的标签的直系文本内容,//text()获取该标签下的所有文本内容。 取属性:/@属性名

3 北京58同城二手房信息爬取

网址信息为bj.58.com/ershoufang/,打开之后页面如下:在这里插入图片描述 导入相关包

import requests
import pandas as pd
from lxml import etree

进行UA伪装,这是十分必须的,因为程序爬虫可能会被网页认为是非法的,所以我们要把程序伪装成浏览器。因此我们要向网页提供系统信息。这个参数可以在网页源码中获取。

headers = {
        'User-Agent' : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.81 Safari/537.36"
    }

在这里插入图片描述 发送一个get请求并获得整个页面响应数据的源码,然后进行局部信息爬取。

url = "https://bj.58.com/ershoufang/"
page_text = requests.get(url = url, headers = headers).text

创建etree实例对象,这里我定义页面编码格式为utf-8,是为了防止一些不是正规的utf-8编码格式的源码而报错。

parse = etree.HTMLParser(encoding='utf-8')
tree = etree.HTML(page_text, parser = parse)

局部标签定位,本次房价信息的获取包括标题、房型、面积、朝向、楼层、建造时间、每平方价格、总价以及地址。在这里插入图片描述 我们的步骤是先定位到相关文本数据所在标签,然后运用 /text() 或者 //text() 函数进行文本获取。在检查网页源码之后,发现所有的文本数据均在属性值为 "list"select 的直系 div 标签中,且类属性值为 "property" ,因此可以先获得 select 下的所有 div 标签。 在这里插入图片描述

div_list = tree.xpath('//section[@ class = "list"]/div[@ class = "property"]')

然后再检查具体信息的标签所在位置,如标题在 div 的直系标签 a 下的第二个直系 div 标签中,且最终位于 h3 标签的 title 属性中。 在这里插入图片描述

title.append(div.xpath('./a/div[2]//h3/@title')[0])#./表示最左边的div

其他数据的获取大同小异,只是在数据的处理上有些不同,比如得到房价的文本数据是有 '\n' 和空格的,要运用字符串的相关函数进行删除。最后就是数据的持久化存储,这里我把房价信息保存为csv文件。

df = pd.DataFrame({"标题" : title, "房型" : fangxing, "面积" : area, "朝向" : chaoxiang, "楼层" : louceng
                   , "建造时间" : time, "每平方米/万元" : one_price, "总房价" : total_price, "地址" : address})
df.to_csv("58同城房价.csv", encoding = "utf-8", index = True, index_label = "序号")

结果: 在这里插入图片描述 完整代码:

#爬取58同城二手房的相关信息
import requests
import pandas as pd
from lxml import etree

if __name__ == "__main__" :
    headers = {
        'User-Agent' : "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/98.0.4758.81 Safari/537.36"
    }
    url = "https://bj.58.com/ershoufang/"
    page_text = requests.get(url = url, headers = headers).text
    #数据解析
    parse = etree.HTMLParser(encoding='utf-8')
    tree = etree.HTML(page_text, parser = parse)
    div_list = tree.xpath('//section[@ class = "list"]/div[@ class = "property"]')
    # print(div_list)
    title, fangxing, area, chaoxiang, louceng, time, total_price, one_price, address = [], [], [], [], [], [], [], [], []
    for div in div_list :
        #标题
        title.append(div.xpath('./a/div[2]//h3/@title')[0])#./表示最左边的div
        #房型
        fangxing_temp = div.xpath('./a//div[@ class = "property-content-info"]/p[1]//text()')
        s = ""
        for str in fangxing_temp :
            if str != ' ' :
                s += str
        fangxing.append(s)
        #面积
        area_temp = div.xpath('./a//div[@ class = "property-content-info"]/p[2]/text()')
        s = area_temp[0].strip(' \n')
        area.append(s)
        #朝向
        chaoxiang.append(div.xpath('./a//div[@ class = "property-content-info"]/p[3]/text()')[0])
        #楼层
        louceng.append(div.xpath('./a//div[@ class = "property-content-info"]/p[4]/text()')[0].strip(' \n'))
        #建造时间
        time.append(div.xpath('./a//div[@ class = "property-content-info"]/p[5]/text()')[0].strip(' \n'))
        #总房价
        total_price.append(div.xpath('./a//div[@ class = "property-price"]/p[1]//text()')[0] + '万')
        #单价
        one_price.append(div.xpath('./a//div[@ class = "property-price"]/p[2]//text()')[0])
        #地址
        address.append('-'.join(div.xpath('./a//section/div[2]/p[2]//text()')))

    df = pd.DataFrame({"标题" : title, "房型" : fangxing, "面积" : area, "朝向" : chaoxiang, "楼层" : louceng
                       , "建造时间" : time, "每平方米/万元" : one_price, "总房价" : total_price, "地址" : address})
    df.to_csv("58同城房价.csv", encoding = "utf-8", index = True, index_label = "序号")