这是我学习爬虫的笔记,作为备忘,如果可以帮到大家,那就更好了~
从零开始学爬虫(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是个不错的选择,容我先去学习学习……
网友评论