Python爬取链家成都小区信息

事先声明,本人爬虫初学者,实习时需要用到房价数据,故上阵爬虫,水平有限,若有高见,还请多多指教。

 

准备工具:Chrome浏览器、Python3.7、IPython notebook

 

爬虫流程

1.进入网站,观察网站特点

        此处强调一下,请务必不要一上来就开始码代码(很多教程里这样做,但实属大坑)。

        首先,我们要确定好自己要爬取的信息以及数据量。在本例中,笔者需要爬取网站上所有成都的小区的名字+房价。

先上图:

https://cd.lianjia.com/xiaoqu/

        算了图上不了,看起来好丑的样子,就放个URL吧,将就将就。

        显然,这个页面只推荐了30个小区,显然不够笔者塞牙缝的。

        其实这个网站很好爬,笔者点了几下各个地区的链接,神奇的事情发生了:每个地区都推荐了大量的小区,而通过勾选条件筛选框,可以把不同层次的小区分开(不选的话只有30页,并没有列举完)。

        这个时候,我们再单机右键,选择检查,使用小箭头助手查找小区名与房价信息的位置,很轻松地就找到了totalPrice与_blank两个标志性的class。

        每个页面中的信息位置找到了,接下来就是寻找url的特征了,笔者试了几次就发现了,url是由固定前缀+地区名+页名+筛选条件+固定后缀构成的,那么这就轻松了,直接写几个循环构造足够的url即可。

        不不不,事情没有这么简单,除了固定的前缀和后缀以外,地区名可是个大问题,不可能笔者辛辛苦苦自己手打吧?

        其实很简单,我们可以通过鼠标单击链接过去,那么不就说明有现成的url吗?所以我们再次检查,找出url位置,data-role="ershoufang",然后我们就可以从一个地区开始,通过筛选条件与页数构造url,又通过url得到的html页面得到更多的url,如此,我们就可以写好代码慢慢等程序自动爬完了。

2.编写程序

        笔者用的是python的requests库与BeautifulSoup库,简单实用,良心推荐。

        顺便附上实用教程:

http://2.python-requests.org/zh_CN/latest/user/quickstart.html

https://beautifulsoup.readthedocs.io/zh_CN/latest/

        首先,我们通过条件筛选、页数构造两层循环,构造url。

        然后,我们通过url发送get请求。

        接下来就是惊喜的时刻啦,你会发现,毛线都得不到,因为 no access,链家小气得很,不让我们随便爬。

        可那又如何,笔者是那种一遇到困难就放弃的人吗?(显然是,然而实习不得不做)

        链家服务器如何发现我们不是浏览器用户?显然是发送的get请求与正常的浏览器请求不同,了解过http协议的用户都知道,get请求只有请求头,没有请求体,那么事情就简单了。

        我们照样通过浏览器的检查功能,进入network页面,刷新网页,捕获到文档内容,我们打开文档,查看headers信息,恍然醒悟,这里是有cookies信息的!

        那就简单了,笔者偷偷把headers信息与cookies信息复制粘贴到文档中,然后在notebook中对两个文件清洗一下,得到headers与cookies的字典,并在发送get请求时附上headers与cookies,结果完美!

        解决了这个问题,接下来就简单了,我们通过BeautifulSoup库的API轻而易举地得到了url与房价信息,当然,这个过程需要时间,笔者建议,写好代码之后可以稍作休息,拜读拜读笔者的其他文章。

 

附上代码:

import requests
import pandas
from bs4 import BeautifulSoup

def get_price_info(url, cookies, headers):
    dic = {}
    response = requests.get(url, headers=headers, cookies=cookies)
    obj = BeautifulSoup(response.text)
    name_list_raw = BeautifulSoup(str(obj.find_all('div',attrs={'class':'title'})))
    name_list = []
    for item in name_list_raw.select('a'):
        name_list.append(item.string)
    del_one = name_list.pop()
    price_list_raw = BeautifulSoup(str(obj.find_all('div',attrs={'class':'totalPrice'})))
    price_list = []
    for item in price_list_raw.select('span'):
        if item.string != '暂无':
            price_list.append(int(item.string))
    for i in range(len(name_list)):
        dic[name_list[i]] = price_list[i]
    print('The url is %s'%url)
    return dic

def get_price_of_district(name, cookies, headers):
    url = 'https://cd.lianjia.com/xiaoqu/' + name + '/?from=rec'
    price_dic = get_price_info(url, cookies, headers)
    response = requests.get(url, headers=headers, cookies=cookies)
    obj = BeautifulSoup(response.text)
    url_name = obj.select('body > div > div > dl > dd > div > div > a')
    urls = []
    for item in url_name:
        urls.append('https://cd.lianjia.com' + item.get('href'))
    for i in range(2,31):
        url = 'https://cd.lianjia.com/xiaoqu/' + name + '/pg' + str(i) + '/?from=rec'
        try:
            response = requests.get(url, headers=headers, cookies=cookies)
            obj = BeautifulSoup(response.text)
            url_name = obj.select('body > div > div > dl > dd > div > div > a')
            for item in url_name:
                urls.append('https://cd.lianjia.com' + item.get('href'))
            price_dic.update(get_price_info(url, cookies, headers))
        except:
            print('An exception occurs when it comes to '+url)
            continue
    for url in urls:
        try:
            price_dic.update(get_price_info(url, cookies, headers))
        except:
            print('An exception occurs when it comes to '+url)
            continue
    return price_dic

cookie_file = open('/Users/star/Desktop/cookies.txt')
cookies = {}
for line in cookie_file.readlines():
    temp = line.split()
for i in range(int(len(temp)/6)):
    cookies[temp[i*6]] = temp[i*6+1]
header_file = open('/Users/star/Desktop/headers.txt')
headers = {}
for line in header_file.readlines():
    temp = line.strip('\n').split(':')
    headers[temp[0]] = temp[1].strip(' ')
price_dic = get_price_of_district('jinniu', cookies, headers)

        喂喂喂,别急,笔者还有话要说!

        切记,一定要注意异常处理,用上try except,否则一旦任何一个url出现问题,结果保存不了,前面的时间全都浪费了。

        另外,认真阅读的朋友会发现,这里构造的的30页循环其实没有必要,因为我们设置了筛选条件,那么就很可能不足三十页,我们完全可以通过页面下的总页数判断接下来的数量,笔者懒,没有做,但笔者认为,通过“下一页”的链接,可以极大地简化这个过程。

        看在笔者加班写博客的面子上,读者点个赞、转个发、关个注可好?

你可能感兴趣的:(闲来无事)