爬虫(二)selenium爬二手房

我决定爬房价。因为原本的教程,后面也是爬58同城,我也就跟着爬了。不过这次,我是基本都改了。

其实一开始很快就写好了,但是第二页开始就要输入验证码了。我查了下,说selenium可以规避这个问题,我就去安装了这个库。但是还有很多得需要提前安装。 (代码在最下面)

chromedriver

下载地址:http://chromedriver.storage.googleapis.com/index.html

我点开进去后,想着自己的谷歌是最新版本的就直接拉到最下面了。结果扑街了,2.9是2014年发布的。然后我浏览器是version67的,逐个点击了选择最新的,2.41。

解压在谷歌浏览器的目录下面。右键快捷方式 ,打开文件所在位置就好了。是一个Application的文件夹。先复制目录,等会会用到。

然后右击‘此电脑’(WIN10)–>属性–>左侧的高级系统设置–>环境变量–>看到下面有个系统变量。

点击新建,变量名随便写个’chromedrive’,然后浏览目录,选择刚才那个复制的目录(Application)。最后保存。

pyecharts

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)

接着按照之前的方法看我们要抓取的数据的标签分别是什么。

爬虫(二)selenium爬二手房_第1张图片
爬虫(二)selenium爬二手房_第2张图片

我们要抓地区还有每平方的价格。查看之后的结果是

/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)

因为位于的

不同,所以在抓取的时候我们还是要先抓
  • 开始爬数据
    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 = {}

    这是要用的package。
    创建一个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

    这个函数通过一个url来得到总共的页数。不过58同城都是70页,我也不知道为什么,所以你可以直接就让times=70也没关系。

    还是一样像开头那样找到xpath之后根据路径来寻找。发现最后一页的路径如下:

    /html/body/div[5]/div[5]/div[1]/div[2]/a[3]/span

    先找到

    的内容,然后在里面的第二个(因为属性都相同,只能find_all之后再选择导数第二个(也就是第三个,a[3])了。

    需要注意的是,driver.get(url)就是发送请求了,因此page_source就是接收的网页。像上一篇文章那样用BeautifulSoup进行解析。

    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
    

    其实也是按照xpath路径寻找到要的内容。

    要解释的是,我们计算的均值是每个地区(广州有天河,白云)的价格除以检测到的该地区的数目(不是很严谨)。

    比如我们检测到一个房子的district和price,首先我们先检测district(地区名)有没有在map_district里面,假如存在,则对应的数目加1,然后对应的价格也加上price。如果没有,则创建一个字典来存储这个地区,num = 1, price =0,再加上这个房子的price。

    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()

    这是运用了百度的pyecharts的Map,来将数据都画成地图的形式。创建一个地图,给一个名字,宽度和高度。迭代之前记录的map_district,如果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()

    这是主程序。没什么好讲的了,还是要自己看的。最后会在文件目录生成一个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 = {}
    
    
    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()
  • 你可能感兴趣的:(爬虫,selenium,爬虫,可视化,二手房价,pyecharts)