我决定爬房价。因为原本的教程,后面也是爬58同城,我也就跟着爬了。不过这次,我是基本都改了。
其实一开始很快就写好了,但是第二页开始就要输入验证码了。我查了下,说selenium可以规避这个问题,我就去安装了这个库。但是还有很多得需要提前安装。 (代码在最下面)
下载地址:http://chromedriver.storage.googleapis.com/index.html
我点开进去后,想着自己的谷歌是最新版本的就直接拉到最下面了。结果扑街了,2.9是2014年发布的。然后我浏览器是version67的,逐个点击了选择最新的,2.41。
解压在谷歌浏览器的目录下面。右键快捷方式 ,打开文件所在位置就好了。是一个Application的文件夹。先复制目录,等会会用到。
然后右击‘此电脑’(WIN10)–>属性–>左侧的高级系统设置–>环境变量–>看到下面有个系统变量。
点击新建,变量名随便写个’chromedrive’,然后浏览目录,选择刚才那个复制的目录(Application)。最后保存。
pyecharts是python的可视化库。我们需要按照这个库之后需要下载地图。有:
pip install echarts-countries-pypkg # 国家地图
pip install echarts-china-provinces-pypkg # 省的地图
pip install echarts-china-cities-pypkg # 市的地图
我只下载了市的,因为只用来爬广州的。
比如我们想要抓取广州的数据,我们可以有:http://gz.58.com/ershoufang/?PGTID=0d200001-0000-3c62-f0fc-52c0419c4d8e&ClickID=2
嗯,看起来这个url杂乱无章。但是你点击第二页就会发现它是这样的:http://gz.58.com/ershoufang/pn2/?PGTID=0d30000c-0000-3859-164a-750fda376cbf&ClickID=1
然后第三页是这样的:http://gz.58.com/ershoufang/pn3/?PGTID=0d30000c-0000-3945-5408-f27d29243517&ClickID=1
emmm,都有pn,那就试下:http://gz.58.com/ershoufang/pn1/ 。成功了!!!这是第一页的网页。祝贺。
所有第i页就是:http://gz.58.com/ershoufang/pn + str(i)
接着按照之前的方法看我们要抓取的数据的标签分别是什么。
我们要抓地区还有每平方的价格。查看之后的结果是
/html/body/div[5]/div[5]/div[1]/ul/li[1]/div[2]/p[2]/span/a[2] (地区,district)
/html/body/div[5]/div[5]/div[1]/ul/li[1]/div[3]/p[2] (价格,price)
因为位于的 这是要用的package。 这个函数通过一个url来得到总共的页数。不过58同城都是70页,我也不知道为什么,所以你可以直接就让times=70也没关系。 还是一样像开头那样找到xpath之后根据路径来寻找。发现最后一页的路径如下: /html/body/div[5]/div[5]/div[1]/div[2]/a[3]/span 先找到 需要注意的是,driver.get(url)就是发送请求了,因此page_source就是接收的网页。像上一篇文章那样用BeautifulSoup进行解析。 其实也是按照xpath路径寻找到要的内容。 要解释的是,我们计算的均值是每个地区(广州有天河,白云)的价格除以检测到的该地区的数目(不是很严谨)。 比如我们检测到一个房子的district和price,首先我们先检测district(地区名)有没有在map_district里面,假如存在,则对应的数目加1,然后对应的价格也加上price。如果没有,则创建一个字典来存储这个地区,num = 1, price =0,再加上这个房子的price。 这是运用了百度的pyecharts的Map,来将数据都画成地图的形式。创建一个地图,给一个名字,宽度和高度。迭代之前记录的map_district,如果 总价格除以总数目得出来均值,那么我们用 这是主程序。没什么好讲的了,还是要自己看的。最后会在文件目录生成一个html文件,用浏览器打开。接下来估计要学xpath和其他的库。 最终的效果: 接下来是全部的代码,要注意的是,那些文件保存的路径需要自己改:
开始爬数据
from bs4 import BeautifulSoup
from selenium import webdriver
from pyecharts import Map
import re
driver = webdriver.Chrome(executable_path='C:/Program Files (x86)/Google/Chrome/Application/chromedriver.exe')
map_district = {}
创建一个webdrive.Chrome对象,路径选择之前安装的chromedrive.exe路径。
创建一个词典,里面会存储放进去地图的值(这次用pyecharts的Map可视化)。def get_page_num(url):
driver.get(url)
html = driver.page_source
soup = BeautifulSoup(html, 'lxml')
pages = soup.find('div', attrs={'class': 'pager'})
page = pages.find_all('a')[-2]
return page
(因为属性都相同,只能find_all之后再选择导数第二个(也就是第三个,a[3])了。
def get_data(url):
driver.get(url)
html = driver.page_source
soup = BeautifulSoup(html, 'lxml')
theme = soup.find('ul', attrs={"class": "house-list-wrap"})
Tags = theme.find_all('li')
for li in Tags:
try:
li
try:
div_2 = li.find('div', attrs={"class": "list-info"})
p_2 = div_2.find_all('p', attrs={'class': 'baseinfo'})[1]
a = p_2.find_all('a', attrs={'target': '_blank'})[1]
district = a.text.strip()
div_3 = li.find('div', attrs={"class": "price"})
p = div_3.find('p', attrs={'class': 'unit'}).text.strip()
price = re.match('(.+)元/㎡', p)
real_price = price.group(1)
if map_district.get(district):
map_district[district]['num'] += 1
else:
map_district[district] = {}
map_district[district]['num'] = 1
map_district[district]['price'] = 0
map_district[district]['price'] += int(real_price)
except:
continue
except:
continue
def drwa_map(name):
name.upper()
map = Map(name + '二手房均价', width=1200, height=600)
names = []
dis_price = []
for name, dic in map_district.items():
# this one should be changed
if name == '广州':
continue
else:
names.append(name+'区')
dis_price.append(int(dic['price'] / dic['num']))
# this maptype should be changed
map.add('二手房价', attr=names, value=dis_price, maptype='广州', is_map_symbol_show=False, is_visualmap=True,
visual_text_color='#000', visual_range=[5000, 100000])
map.render()
name=='广州'
,不理会。因为地图没有广州的选项,只有各个区的选项。我也不知道为什么58不细分下去。map.add
把数据加进去地图加载。maptype
是选择加载的地图。is_map_symbol_show
会在不同区域标记红色点,我选择了False。visual_range
可以自己调整,是可以看的数据范围。def main():
# change the city
city = 'gz'
url = 'http://'+city + '.58.com/ershoufang/pn'
# get the pages number
times = int(get_page_num(url+'1/').text.strip())
for i in range(1, times+1):
url_object = url + str(i) + '/'
get_data(url_object)
print('正在爬取第 %s 页' % i)
print('Total pages: {}'.format(times))
drwa_map(city)
if __name__ == "__main__":
main()
from bs4 import BeautifulSoup
from selenium import webdriver
from pyecharts import Map
import re
driver = webdriver.Chrome(executable_path='C:/Program Files (x86)/Google/Chrome/Application/chromedriver.exe')
map_district = {}
def get_page_num(url):
driver.get(url)
html = driver.page_source
soup = BeautifulSoup(html, 'lxml')
pages = soup.find('div', attrs={'class': 'pager'})
page = pages.find_all('a')[-2]
return page
def get_data(url):
driver.get(url)
html = driver.page_source
soup = BeautifulSoup(html, 'lxml')
theme = soup.find('ul', attrs={"class": "house-list-wrap"})
Tags = theme.find_all('li')
for li in Tags:
try:
li
try:
div_2 = li.find('div', attrs={"class": "list-info"})
p_2 = div_2.find_all('p', attrs={'class': 'baseinfo'})[1]
a = p_2.find_all('a', attrs={'target': '_blank'})[1]
district = a.text.strip()
div_3 = li.find('div', attrs={"class": "price"})
p = div_3.find('p', attrs={'class': 'unit'}).text.strip()
price = re.match('(.+)元/㎡', p)
real_price = price.group(1)
if map_district.get(district):
map_district[district]['num'] += 1
else:
map_district[district] = {}
map_district[district]['num'] = 1
map_district[district]['price'] = 0
map_district[district]['price'] += int(real_price)
except:
continue
except:
continue
def drwa_map(name):
name.upper()
map = Map(name + '二手房均价', width=1200, height=600)
names = []
dis_price = []
for name, dic in map_district.items():
# this one should be changed
if name == '广州':
continue
else:
names.append(name+'区')
dis_price.append(int(dic['price'] / dic['num']))
# this maptype should be changed
map.add('二手房价', attr=names, value=dis_price, maptype='广州', is_map_symbol_show=False, is_visualmap=True,
visual_text_color='#000', visual_range=[5000, 100000])
map.render()
def main():
# change the city
city = 'gz'
url = 'http://'+city + '.58.com/ershoufang/pn'
# get the pages number
times = int(get_page_num(url+'1/').text.strip())
for i in range(1, times+1):
url_object = url + str(i) + '/'
get_data(url_object)
print('正在爬取第 %s 页' % i)
print('Total pages: {}'.format(times))
drwa_map(city)
if __name__ == "__main__":
main()