一、简介
用途:此程序为爬取链家各城市楼盘信息并存入csv文件中
环境:pthon3
库:requests、re、bs4、pandas
链家新房楼盘网址:https://sh.fang.lianjia.com/loupan/
二、思路及流程
- 目标:
爬取各个地区的:楼盘名称、地理位置、均价 - 目标定位分析:
1.观察发现每个楼盘信息都存放于标签li中()
2.标签a存放了楼盘名及具体地址(用属性class和href定位)
3.标签span存放了地点信息及价格信息! - 链接变换分析:
- 地区变化:
上海:https://sh.fang.lianjia.com/loupan/
合肥:https://hf.fang.lianjia.com/loupan/
地区首字母缩写控制地区变化 - 单个地区内翻页变化(上海为例)
第一页: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.pngimage.pngimage.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#若某个楼盘解析失败,使循环能继续
目标定位:
-
楼盘名定位特征(上海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