想要生成热力分布图,首先要爬取房价的数据,所以第一步,我们先把爬虫写出来。
一 确定目标URL,实现爬虫,代码如下:
import urllib.request
from urllib.request import HTTPError
import json
from multiprocessing import Pool
import lxml
import csv
from bs4 import BeautifulSoup
import requests
#数据要放到execl里,所以先新建execl文件
file = open('dc.csv', 'w', newline='',encoding='utf-8')
headers = ['name', 'pattern','area','floor',"Heading",'time','Total price','price','loc']
writers = csv.DictWriter(file, headers)
writers.writeheader()
#该函数是调用百度地图APi接口,获取经纬度
def getlocation(name):#调用百度API查询位置
bdurl='http://api.map.baidu.com/geocoder/v2/?address='
output='json'
ak=''#输入你刚才申请的密匙
callback='showLocation'
uri=bdurl+name+'&output=t'+output+'&ak='+ak+'&callback='+callback
res=requests.get(uri)
s=BeautifulSoup(res.text)
lng=s.find('lng')
lat=s.find('lat')
if lng:
return lng.get_text()+','+lat.get_text()
#该函数以模拟浏览器方式登陆,获取User-Agent
def Pretend():
headers = ("User-Agent",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36 SE 2.X MetaSr 1.0")
openera = urllib.request.build_opener()
openera.addheaders = [headers]
urllib.request.build_opener(openera)
#因为功能为迭代的,所以我们把爬取一个网页的逻辑封装在一个函数里
def get_one_page(url):
try:
response = urllib.request.urlopen(url).read().decode('utf-8')
except HTTPError as e:
print(e)
return response
#该函数用正则表达式来匹配我们想要的数据
def parse_esf_price(esful):
html = get_one_page(esful)
pattern = re.compile(
'<p class="house-title">.*?<a.*?>(.*?)</a>.*?<span>(.*?)</span>.*?<span>(.*?)</span>.*?<span>(.*?)</span>.*?<span>(.*?)</span>'
+ '.*?''<span>(.*?)</span>.*?<div class="show-price">.*?<span.*?>(\d+)</span><span.*?>(.*?)</span>.*?<p>(.*?)</p>',
re.S)
info = re.findall(pattern, html)
for infos in info:
yield {
'name': infos[0],
'pattern': infos[1],
'area': infos[2],
'floor': str.strip(infos[3]),
'Heading': infos[4],
'time': infos[5],
'Total price': infos[6],
'price': infos[8],
'loc':getlocation(infos[0])
}
def main(offset):
url = 'http://zhuhai.qfang.com/sale/' + 'f' + str(offset)
html = get_one_page(url)
for item in parse_esf_price(url):
print(item)
writers.writerow(item)
if __name__ == '__main__':
url = "http://zhuhai.qfang.com/"
pool = Pool()
pool.map(main, [i for i in range(100)])
上述代码讲以下几点:
1 ,再写爬虫之时不建议用正则表达式,可以用bs4来抓取节点,也可以用xpath来获取,xpath更加的广泛。因为网页的html源码是要改的,如果用了正则表达式,那么就不好维护,因为博主的代码是刚学爬虫时写的,没写进类里面,也没用xpath,没有时间进行改良,但是还是好用的,可以拷过去运行,前提是该有的模块都有。
2,如果不用scrapy框架,在多数据爬取时,会显得很脆弱,会很卡,所以这里用了多进程来实现。也就是Pool类。
3,多网页爬取时,要总结网页偏移的规律。来构造URL地址。也可以在网页源码中提取,看个人习惯。
4,生成热力图,离不开百度地图API,我们实现这个其实就是把小区的名字转换成经纬度。进入百度地图API官网,注册开发者账号,申请密钥。这里注意,我们最后生成的其实是一个html文件。所以在选择平台时我们要选择浏览器端。refer白名单我们填写*,填写0.0.0.0不好使。
二 申请百度API流程如下:
网址:http://lbsyun.baidu.com/
进入首页后,点击功能与服务,接着点击地图,再点击左侧的获取密钥,这时进入了创建应用的界面。点击创建应用,名称随便写。但是应用类别要选择浏览器端。创建完成之后 AK便是我们的密钥。
随后进入http://lbsyun.baidu.com/index.php?title=jspopular这个网址。也就是webAPI,我们点击左侧的示例demo选项。在左侧的覆盖物示例中,点击添加热力图。这时可以看出,我们最后生成的HTML文件的源码就是这个,只不过AK要改成你申请的密钥,点击运行之后才可以复制下来,这里注意几点,第一点,百度地图默认北京天安门,你要在var point = new BMap.Point(113.5832319144, 22.2763968747); map.centerAndZoom(point, 15); 这两句代码中改。这里我改成了珠海的经纬度和城市级别。
第二:
{"lng":113.572877701,"lat":22.2852944661,"count":105},
{"lng":113.541354798,"lat":22.2702942392,"count":320},{"lng":113.553078868,"lat":22.27334793,"count":1180},我们通过最后爬取的经纬度就是要填写到这里才行,但是由于这个格式是json的,所以我们要把execl文件里的该数据按照json数据打印到控制台中,在进行复制粘贴。
二 经纬度转换。
import csv
reader=csv.reader(open('dc.csv',encoding='utf-8'))
for row in reader:
loc=row[8]
sloc=loc.split(',')
lng=''
lat=''
if len(sloc)==2:#第一行是列名需要做判断
lng=sloc[0]
lat=sloc[1]
count=row[6]
out='{\"lng\":'+lng+',\"lat\":'+lat+',\"count\":'+count+'},'
print(out)
我们可以把这段代码令写一个文件里。先运行爬虫里的,生成execl之后,在运行这个py文件,就可在控制台输出json数据格式的经纬度了,这里注意 count是最后热力分布的量,你可以用任何数值来标定,这里我用的是价格,你也可以用关注度,单平米的价格来标定,在复制粘贴到你的html文件里,再点击网页,就可以生成热力图了。
展示如下:
如有不懂留言评论。