Python网络爬虫实战-爬取链家各城市新房楼盘信息,保存为csv文件

一、简介

用途:此程序为爬取链家各城市楼盘信息并存入csv文件中
环境:pthon3
库:requests、re、bs4、pandas
链家新房楼盘网址:https://sh.fang.lianjia.com/loupan/

二、思路及流程

  • 目标:
    爬取各个地区的:楼盘名称、地理位置、均价
  • 目标定位分析:
    1.观察发现每个楼盘信息都存放于标签li中()
    2.标签a存放了楼盘名及具体地址(用属性class和href定位)
    3.标签span存放了地点信息及价格信息!
  • 链接变换分析:
  1. 地区变化:
    上海:https://sh.fang.lianjia.com/loupan/
    合肥:https://hf.fang.lianjia.com/loupan/
    地区首字母缩写控制地区变化
  2. 单个地区内翻页变化(上海为例)
    第一页:https://sh.fang.lianjia.com/loupan/
    第二页:https://sh.fang.lianjia.com/loupan/pg2/
    第三页:https://sh.fang.lianjia.com/loupan/pg3/
    以pg+数字控制
目标信息:
image.png
源代码分析
image.png

image.png

image.png

image.png
  • 全部地区url获取
    选取上海作为初始链接,获取全部地区


    image.png
    image.png

    源代码分析
    image.png
  • 解析流程:
    1.获取所有li标签,方法:soup.find_all('tag',attrs={'key':"value"})
    2.获取其中的所有a标签和span标签,并筛选
    方法:tag.string()获取标签内容、tag['attrs']获取标签属性的值

三、程序架构及函数实现

架构

def getHTMLText(url):#爬取一个html页面
def get_url(start_url, Dict):#从初始链接获取其他城市的url,并存入字典内
def parsePage(html, List):#提取每个地区的楼盘信息,并存入列表内(每个地区100页)
def writeIn_csv(List, name):#将列表转换并写入csv文件以name名门
def Text_progress_bar(JDcount, Zcount):#文本进度条
def main():

实现

1. 爬取一个html页面

def getHTMLText(url):
    headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'}
    try:
        r = requests.get(url, headers = headers, timeout = 30)
        r.raise_for_status()#若返回页面状态码不是200则返回HttpError的异常
        #已知获取的页面编码为utf-8编码,定向爬虫取消编码替换以提高效率
        #r.encoding = r.apparent_encoding
        return r.text#返回一个 unicode 型的文本数据
    except:
        print(" --此页爬取失败--")
        return ""#爬取失败返回空字符串

2. 获取其他城市的url,并存入字典内

def get_url(start_url, Dict):#从初始链接获取其他城市的url
    html = getHTMLText(start_url)
    soup = BeautifulSoup(html, "html.parser")
    #城市信息存于a标签内,以属性title标签定位。re.compile('房产网')正则表达式
    all_city = soup.find_all('a', title=re.compile('房产网'))
    for city in all_city:
        name = city.string#城市名(tag.string获取标签的内容)
        urll = city['href']#链接(tag['attrs']获取属性的值)
        Dict[name] = urll#存入字典
1.png

3. 提取每个地区的楼盘信息,并存入列表内

def parsePage(html, List):#提取每个地区的楼盘信息(每个地区100页)
    soup = BeautifulSoup(html, "html.parser")
    #print(soup.prettify())美化html页面
    #楼盘信息都封装在li标签内(含垃圾数据)
    cut_tag_li = soup.find_all('li')    
    for li in cut_tag_li:     
        pakege = []#列表-存放每个楼盘信息的载体
        try:
            #提取楼盘名
            tag_a = li.find('a', attrs={'class':"resblock-img-wrapper"})
            loupan = tag_a['title'] 

            #提取地点
            tag_span = li.find_all('span')
            city = tag_span[2].string#周边  
            area = tag_span[3].string#城市 
            #具体地址
            tag_a = li.find_all('a', attrs={'href':re.compile('/#around')})
            location = tag_a[-1].string

            #提取价格
            price_tag_span = li.find_all('span', attrs={'class':"number"})
            price = price_tag_span[-1].string
         
            address = city + '\n' + area + '\n' + location
            #将每个楼盘信息暂存入列表pakege
            #List..append()方法用于在列表末尾添加一个新的对象,只能接收一个参数
            pakege.append(loupan)
            pakege.append(address)
            pakege.append(price)
            #将pakege添加到List
            List.append(pakege)
        except:
            continue#若某个楼盘解析失败,使循环能继续

目标定位:

  1. 楼盘名定位特征(上海vs合肥)


    楼盘名1.png

    image.png

    2.地理位置定位特征


    地点.png

    3.价格定位特征
    价格.png

4. 将列表转换并写入csv文件

#用pandas库写入csv文件
def writeIn_csv(List, name):
    try:
        title = ['楼盘', '位置', '价格']
        file = pd.DataFrame(columns=title, data=List)#数据有三列对应loupan、adress、price
        #print(file)
        file_name = 'C:/Users/dell/Desktop/全国/' + name + '.csv'
        file.to_csv(file_name, encoding='utf_8_sig')#两个参数文件名(路径)和编码方式
        print('%s写入csv文件成功' %(name))
    except:
        print('%s写入csv文件失败' %(name))

pandas写入csv文件理解如图
参考原文:https://blog.csdn.net/weixin_40096730/article/details/81255136

image.png

5. 文本进度条

此文本进度条在总量数字较小时误差较大。。。

#文本进度条
def Text_progress_bar(JDcount, Zcount):#参数(进度,总量)
    lenth = 30 #控制进度条长度,以比例显示进度
    a = '*' * int( (JDcount/Zcount) * lenth )
    b = '.' * int( lenth - (JDcount/Zcount) * lenth )
    print("\r[{}->{}]进度{:.2f}%".format( a, b, JDcount*100/Zcount ), end='')

6.main()函数

def main():
    count = 2 #爬取的城市数
    depth = 2 #每个城市爬取页数
    JDcount = 0
    Dict = {} #存放各城市及其url

    start_url = 'https://sh.fang.lianjia.com/loupan/#pudong'
    get_url(start_url, Dict)#从初始链接获取其他城市的url
    #遍历获取所有城市,count控制数量
    for dic in Dict:
        List = [] #列表-载体-存放每个城市楼盘信息
        count -= 1
        JDcount += 1
        if count < 0:#城市数量<0时跳出
            break

        name = dic#城市名(字典的key)
        name_url = Dict[dic]#城市url(字典的value)        
        url = 'https:' + name_url + '/loupan/pg'#合成每个城市的url
        print('{}.正在爬取城市-{}'.format(JDcount, name))
        for i in range(depth):#每个城市爬取深度(页面数)
            Text_progress_bar(i, depth)#进度条
            new_url = url + str(i) + '/'
            html = getHTMLText(new_url)
            parsePage(html, List)
        
        writeIn_csv(List, name)#写入csv文件

四、完整代码

'''
此程序为爬取链家各城市楼盘信息
分析:
1.观察发现每个楼盘信息都存放于标签li中()
2.标签a存放了楼盘名及具体地址(用属性class和href定位)
3.标签span存放了地点信息及价格信息
解析流程:
1.获取所有li标签,方法:soup.find_all()
2.获取其中的所有a标签和span标签,并筛选
'''
import requests
import re
from bs4 import BeautifulSoup
import pandas as pd
def getHTMLText(url):
    headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36'}
    try:
        r = requests.get(url, headers = headers, timeout = 30)
        r.raise_for_status()
        #获取的页面编码为utf-8
        '''
        print(r.encoding)
        print(r.apparent_encoding)
        r.encoding = r.apparent_encoding
        '''
        #print(" --此页爬取成功--")
        return r.text
    except:
        print(" --此页爬取失败--")
        return ""

def get_url(start_url, Dict):#从初始链接获取其他城市的url
    html = getHTMLText(start_url)
    soup = BeautifulSoup(html, "html.parser")
    all_city = soup.find_all('a', title=re.compile('房产网'))
    for city in all_city:
        name = city.string#城市名
        urll = city['href']#链接
        Dict[name] = urll#存入字典

    #print(Dict)

def parsePage(html, List):#提取每个地区的楼盘信息(每个地区100页)
    soup = BeautifulSoup(html, "html.parser")
    #print(soup.prettify()) 美化
    #楼盘信息都封装在li标签内(有垃圾数据)
    tag_li = soup.find_all('li')   
    cut_tag_li = tag_li[:]
    #print(len(tag_li))#389 366-376
    #print(len(cut_tag_li))
    
    for li in cut_tag_li:     
        pakege = []#列表-存放每个楼盘信息的载体
        try:
            #提取楼盘名
            tag_a = li.find('a', attrs={'class':"resblock-img-wrapper"})
            loupan = tag_a['title'] 

            #提取地点
            tag_span = li.find_all('span')
            city = tag_span[2].string#周边  
            area = tag_span[3].string#城市 
            #具体地址
            tag_a = li.find_all('a', attrs={'href':re.compile('/#around')})
            location = tag_a[-1].string

            #提取价格
            price_tag_span = li.find_all('span', attrs={'class':"number"})
            price = price_tag_span[-1].string
 
            address = city + '\n' + area + '\n' + location
            #将每个楼盘信息暂存入列表pakege
            #List..append()方法用于在列表末尾添加一个新的对象,只能接收一个参数
            pakege.append(loupan)
            pakege.append(address)
            pakege.append(price)
            #将pakege添加到List
            List.append(pakege)
        except:
            #print("楼盘解析失败")
            continue
    #print(List) 

#用pandas库写入csv文件
def writeIn_csv(List, name):
    try:
        title = ['楼盘', '位置', '价格']
        file = pd.DataFrame(columns=title, data=List)#数据有三列
        #print(file)
        file_name = 'C:/Users/dell/Desktop/全国/' + name + '.csv'
        file.to_csv(file_name, encoding='utf_8_sig')
        print('%s写入csv文件成功' %(name))
    except:
        print('%s写入csv文件失败' %(name))

#文本进度条
def Text_progress_bar(JDcount, Zcount):#参数(进度,总量)
    lenth = 30 #控制进度条长度,以比例显示进度
    a = '*' * int( (JDcount/Zcount) * lenth )
    b = '.' * int( lenth - (JDcount/Zcount) * lenth )
    print("\r[{}->{}]进度{:.2f}%".format( a, b, JDcount*100/Zcount ), end='')

def main():
    count = 2 #爬取的城市数
    depth = 2 #每个城市爬取页数
    JDcount = 0
    Dict = {} #存放各城市及其url

    start_url = 'https://sh.fang.lianjia.com/loupan/#pudong'
    get_url(start_url, Dict)#从初始链接获取其他城市的url
    #遍历获取所有城市,count控制数量
    for dic in Dict:
        List = [] #列表-载体-存放每个城市楼盘信息
        count -= 1
        JDcount += 1
        if count < 0:#城市数量<0时跳出
            break

        name = dic#城市名(字典的key)
        name_url = Dict[dic]#城市url(字典的value)        
        url = 'https:' + name_url + '/loupan/pg'#合成每个城市的url
        print('{}.正在爬取城市-{}'.format(JDcount, name))
        for i in range(depth):#每个城市爬取深度(页面数)
            Text_progress_bar(i, depth)#进度条
            new_url = url + str(i) + '/'
            #print('\n正在爬取第{}页:'.format(i+1) + new_url)
            html = getHTMLText(new_url)
            parsePage(html, List)
        
        writeIn_csv(List, name)#写入csv文件

main()

五、运行结果

运行.png

结果.png

image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。