一、简介
用途:此程序为爬取链家各城市楼盘信息并存入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.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
#若某个楼盘解析失败,使循环能继续
目标定位:
楼盘名定位特征(上海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