Python数据采集与爬虫Python 爬虫专栏爬虫

从零开始学爬虫(2):突破限制,分类爬取,获得全部数据

2017-02-16  本文已影响829人  BruceYeen

这是我学习爬虫的笔记,作为备忘,如果可以帮到大家,那就更好了~
从零开始学爬虫(1):爬取房天下二手房信息
从零开始学爬虫(2):突破限制,分类爬取,获得全部数据
从零开始学爬虫(3):通过MongoDB数据库获取爬虫数据

上一篇爬取房天下二手房信息我们可以看到的信息有一个100页的限制,下面我们尝试通过分类爬取的方法获得全部数据。

一、了解网站反爬限制

以房天下二手房信息为例,不论选择哪一级分类标签,最高显示的页数上限都是100,如下图:

图片.png
图片.png

想要突破这层限制,只需要把找房条件不断细化,直至符合条件的信息不足100页即可(如下图)。

图片.png

而每多一个筛选条件,URL就会发生一次变化,笔者试图从中发现一些规律,但没有成功,以下是按照城南不同区域的一些URL:

城南:
南稍门:http://esf.xian.fang.com/house-a0478-b04113/
明德门:http://esf.xian.fang.com/house-a0478-b04122/
三森:http://esf.xian.fang.com/house-a0478-b04125/
陕师大:http://esf.xian.fang.com/house-a0478-b04126/
文艺路:http://esf.xian.fang.com/house-a0478-b04130/
小寨:http://esf.xian.fang.com/house-a0478-b04131/
吉祥村:http://esf.xian.fang.com/house-a0478-b04635/
省人民医院:http://esf.xian.fang.com/house-a0478-b04884/
……

可以看到,这些URL并没有什么明显的规律,因此,我们先写一段小程序,把这些筛选条件对应的URL都爬下来,然后再按照这些URL去爬取每一页的信息。

二、爬取筛选条件的URL

先通过下面一段小程序把每一类筛选条件对应的URL爬下来:

# -*- coding: utf-8 -*-

from bs4 import BeautifulSoup
import requests

response = requests.get('http://esf.xian.fang.com/')
soup = BeautifulSoup(response.text, 'lxml')

regions = soup.select('#list_D02_10 > div.qxName > a')  # 区域
totprices = soup.select('#list_D02_11 > p > a')  # 总价
housetypes = soup.select('#list_D02_12 > a')  # 户型
areas = soup.select('#list_D02_13 > p > a')  # 面积

print('区域href:')
n = 1
while n < 11:
    print(regions[n].get('href'))
    n = n + 1
print('总价href:')
n = 1
while n < 10:
    print(totprices[n].get('href'))
    n = n + 1
print('户型href:')
n = 1
while n < 7:
    print(housetypes[n].get('href'))
    n = n + 1
print('面积href:')
n = 1
while n < 10:
    print(areas[n].get('href'))
    n = n + 1

结果如下:

图片.png

我们看到,如果单独抓取每一类标签的URL,每个前面都有一个house-或者house/,但是实际上多条件筛选的时候完整的URL是下图这样的,

图片.png

所以我们稍微变换一下代码,把这些按照实际的URL格式链接起来:

n = 1
while n < 11:
    m = 1
    while m < 10:
        i = 1
        while i < 7:
            j = 1
            while j < 10:
                print('http://esf.xian.fang.com' + regions[n].get('href') + totprices[m].get('href')[7:-1] + '-' + housetypes[i].get('href')[7:-1] + '-' + areas[j].get('href')[7:])
                j = j + 1
            i = i + 1
        m = m + 1
    n = n + 1

这样一来,得到的结果就比较好了:

图片.png

OK,总共爬下来4860个URL,这么多的URL,想想就够了。。。即便按照我们爬下来URL库挨个进行访问和爬取的话,还存在一个问题:每一个URL下对应的页数具体是多少呢?我们总不能一个一个去点开看吧?而且,这些组合中有可能还存在超过100页的。怎么办呢?

三、细化分类,确保每一类都少于100页

我是这样做的,根据网页上的四种筛选条件,首先选择其中的两个条件组合(区域和户型),把它们的URL和对应的页数爬下来,

# 按照区域和户型先分类看一下
n = 1
while n < 8:
    i = 1
    while i < 7:
        resp1 = requests.get('http://esf.xian.fang.com' + regions[n].get('href') + '-' + housetypes[i].get('href')[7:])
        soup1 = BeautifulSoup(resp1.text, 'lxml')
        pages = soup1.select('#list_D10_01 > span > span')  # 页数
        print('http://esf.xian.fang.com' + regions[n].get('href') + '-' + housetypes[i].get('href')[7:], pages[0].get_text().split('/')[1])
        i = i + 1
    n = n + 3         # 只取1/4/7

根据其生成的页码数,对于达到100页的再进行细分,先用“总价”,再用“面积”,这样一级一级拆分下去,最终使得每一个细分项对应的页数都在100以内,然后再通过上一篇里面从零开始学爬虫(1):爬取房天下二手房信息的讲到的爬虫主函数去逐页爬取(对于其中细分项为空的页面直接略过)即可:

# 对于大于等于100页的进行细分
n = 1
while n < 8:
    i = 1
    while i < 7:
        resp1 = requests.get('http://esf.xian.fang.com' + regions[n].get('href') + '-' + housetypes[i].get('href')[7:], headers=headers)
        soup1 = BeautifulSoup(resp1.text, 'lxml')
        pages = soup1.select('#list_D10_01 > span > span')  # 页数
        if pages and pages[0].get_text().split('/')[1] == '100':
            m = 1
            while m < 10:
                resp1 = requests.get('http://esf.xian.fang.com' + regions[n].get('href') + totprices[m].get('href')[7:-1] + '-' + housetypes[i].get('href')[7:], headers=headers)
                soup1 = BeautifulSoup(resp1.text, 'lxml')
                pages = soup1.select('#list_D10_01 > span > span')  # 页数
                if pages and pages[0].get_text().split('/')[1] == '100':
                    j = 1
                    while j < 10:
                        resp1 = requests.get('http://esf.xian.fang.com' + regions[n].get('href') + totprices[m].get('href')[7:-1] + '-' + housetypes[i].get('href')[7:-1] + '-' + areas[j].get('href')[7:], headers=headers)
                        soup1 = BeautifulSoup(resp1.text, 'lxml')
                        pages = soup1.select('#list_D10_01 > span > span')  # 页数
                        if pages:
                            k = int(pages[0].get_text().split('/')[1])
                            while k > 0:
                                spider_1('http://esf.xian.fang.com' + regions[n].get('href') + totprices[m].get('href')[7:-1] + '-' + housetypes[i].get('href')[7:-1] + '-' + areas[j].get('href')[7:-1] + '-i3' + str(k))
                                k = k - 1
                                time.sleep(2)
                        else:
                            pass
                        j = j + 1
                else:
                    if pages:
                        k = int(pages[0].get_text().split('/')[1])
                        while k > 0:
                            spider_1('http://esf.xian.fang.com' + regions[n].get('href') + totprices[m].get('href')[7:-1] + '-' + housetypes[i].get('href')[7:-1] + '-i3' + str(k))
                            k = k - 1
                            time.sleep(2)
                    else:
                        pass
                m = m + 1
        else:
            if pages:
                k = int(pages[0].get_text().split('/')[1])
                while k > 0:
                    spider_1('http://esf.xian.fang.com' + regions[n].get('href') + housetypes[i].get('href')[7:-1] + '-i3' + str(k))
                    k = k - 1
                    time.sleep(2)
            else:
                pass
        i = i + 1
    n = n + 3         # 只取1/4/7

四、后记

这样爬下来的数据量太大,最好直接导出到本地存储,那么具体如何操作呢?
  据说MongoDB是个不错的选择,容我先去学习学习……

上一篇 下一篇

猜你喜欢

热点阅读