1、 背景

本实例爬取小猪网沈阳房源信息,使用request、bs4。
简单爬取title、address、price、name、sex等信息。未保存信息。

2、场景分析

2.1 小猪网沈阳(https://sy.xiaozhu.com/)打开后有一个房源列表

右侧为房源图表列表

Python 爬虫 爬房价数据 爬虫爬取房源信息_html

2.2 房源列表分析

a、使用chrome浏览器

b、F12进行源文件分析

c、鼠标点源文件左上角的“箭头”,再点任一房源位置

d、找到源代码中的房源a链接部分,右键a链接后“copy”->“copy selector”,复制需要css 选择器供bs4使用

Python 爬虫 爬房价数据 爬虫爬取房源信息_Python 爬虫 爬房价数据_02

2.3 房源详细信息分析

点击2.2房源列表中的任一房源,进入房源详细信息。需要爬虫的具体内容选择方法同上

Python 爬虫 爬房价数据 爬虫爬取房源信息_ide_03

2.3 房源page信息分析

房源列表分析页面的下面有数字的列表,使用2.2的方法,可以获取到不同page的url信息

Python 爬虫 爬房价数据 爬虫爬取房源信息_html_04

功能实现

import requests # 导入爬虫模块
from bs4 import BeautifulSoup #导入分析库模块
result = requests.get('https://sy.xiaozhu.com/')
soup = BeautifulSoup(result.text,'lxml')

房源url列表

houre_links = soup.select('#page_list > ul > li > a')

打印房源url

for lik in houre_links:
    print(lik['href'])
# houre_links  #page_list > ul > li:nth-child(2) > a
https://sy.xiaozhu.com/fangzi/24328800703.html
https://sy.xiaozhu.com/fangzi/91690139803.html
https://sy.xiaozhu.com/fangzi/11307220860.html
。。。

使用css选择器获取房源基本信息

rs = requests.get('https://sy.xiaozhu.com/fangzi/5950030916.html')
soup1 = BeautifulSoup(rs.text, 'lxml')
title = soup1.select('div > h4 > em')[0].get_text()
address = soup1.select('div.con_l > div.pho_info > p')[0]['title']
price = soup1.select('#pricePart > div.day_l > span')[0].get_text()
image_url = soup1.select('#curBigImage')[0]['src']
name = soup1.select('.lorder_name')[0].get_text()
sex = soup1.select('.member_boy_ico')[0].get_text()

保存房源图片,需要加上headers,否则爬取图片会报403错误

import os
def save_house_image(url, name):
    name = str.replace(name, '/', '')
    os.makedirs('images', exist_ok=True)
    headers = {
        'Referer': url,
        'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 Safari/537.36'
    }
    with open('images/' + name + '.png', 'wb') as f:
        rs = requests.get(url,headers=headers)
        rs.raise_for_status()# 此处可以加上try…except…处理异常
        for chunk in rs.iter_content(100000): #保存二进制文件
            f.write(chunk)

获取房源详细信息

def get_info(url):
    rs = requests.get(url)
    soup1 = BeautifulSoup(rs.text, 'lxml')
    title = soup1.select('div > h4 > em')[0].get_text() # 标题
    address = soup1.select('div.con_l > div.pho_info > p')[0]['title'] # 地址
    price = soup1.select('#pricePart > div.day_l > span')[0].get_text() # 价格
    image_url = soup1.select('#curBigImage')[0]['src'] # 图像URL
    name = soup1.select('.lorder_name')[0].get_text() # 房主昵称
    sex = '男'
    try:
        sex = soup1.select('.member_boy_ico')[0].get_text() # 房主性别
        if sex:
            real_sex = sex
        else:
            real_sex = '女'
    except:
        real_sex = '女'
    # 返回的房源详细信息,根据需要可以选择保存
    info = {
        'title': title,
        'address': address,
        'price': price,
        'image_url': image_url,
        'name': name,
        'sex': real_sex
    }
#     print(info)

    # 保存图片
    save_house_image(image_url, title)
    return info

获取房源列表页面所有房源的url列表和能获取到的page页面url信息

import requests
from bs4 import BeautifulSoup

def get_links(url):
    result = requests.get(url)
    soup = BeautifulSoup(result.text,'lxml')
    # 获取当前页
    active_page = soup.select('.active_link')[0].get_text()
    print('当前页为:%s' % active_page)
    # 获取当前可以获取的page列表
    page_list = soup.select('div.pagination_v2.pb0_vou a') #page_list > div.pagination_v2.pb0_vou
    for page_num in page_list:
        try: # 有些page是< > ...开头通过轻质int类型转换异常抛弃
            num = int(page_num.get_text())
            # 将page页保存在字典中
            page_lists[num] = page_num['href']
        except:
            print('无用page页面,pass')
    
    houre_links = soup.select('#page_list > ul > li > a')
    for lik in houre_links:
        print(lik['href']) # 打印房源详情页url
        get_info(lik['href']) # 调用方法获取房源的详细信息

递归函数从第一页开始爬取
刚开始用while循环会重复爬取,没详细定位,改完递归函数后OK

finsh_num = {} # 已完成爬取的page页字典
page_lists = {1: 'https://sy.xiaozhu.com/'} # 获取到的全部page页字典
def xiaozhu_spider():
    for k in list(page_lists):
        if k not in finsh_num:
            get_links(page_lists[k])
            finsh_num[k] = page_lists[k]
            print('已完成爬取页面: %s' %finsh_num)
            print('全部页面: %s' % page_lists)
    # 已完成爬取的page页 等于 获取到的全部page页相同表示爬取完毕
    if finsh_num == page_lists:
        print('已全部爬取完毕')
        return
    else:#没有爬取完进入递归
        xiaozhu_spider()
xiaozhu_spider()