本來今天還想說試試昨天剛弄的代理池,去爬下鏈家上面的房源信息香追,結(jié)果今天突然發(fā)現(xiàn)合瓢,鏈家的反爬蟲沒有啦~~
趕緊上scrapy,把上面的在售房源信息擼下來透典。
其實很簡單的爬蟲晴楔,用框架有點大材小用了,不過真的比普通多進程快好多呀峭咒,作為一個老男人税弃,快既是追求,也是必然凑队!
至于scrapy的設(shè)置则果,就settings里打開了default request headers和item-pipeline,關(guān)閉了robots協(xié)議,pipelines里面復(fù)制了別人的代碼西壮,還是用mongodb存數(shù)據(jù)遗增。
distinfo.csv 和log.txt 用來存些需要用的信息,好像可以設(shè)置middlewares款青,可是呢做修,我不會。可都。缓待。
import pymongo
class SzlianjiaPipeline(object):
collection_name = 'sz_onsale'
def __init__(self, mongo_uri, mongo_db):
self.mongo_uri = mongo_uri
self.mongo_db = mongo_db
@classmethod
def from_crawler(cls, crawler):
return cls(
mongo_uri=crawler.settings.get('MONGO_URI'),
mongo_db=crawler.settings.get('MONGO_DATABASE')
)
def open_spider(self, spider):
self.client = pymongo.MongoClient(self.mongo_uri)
self.db = self.client[self.mongo_db]
def close_spider(self, spider):
self.client.close()
def process_item(self, item, spider):
self.db[self.collection_name].update({'房屋鏈接':item['房屋鏈接']},dict(item),True)
return item
【絲路在哪里】
反正scrapy的爬蟲設(shè)計就是一層一層往下爬,咱就從首頁開始渠牲,先獲取區(qū)域鏈接旋炒,
def parse_dist(self,response):
dists = response.xpath('//div[@data-role="ershoufang"]/div/a/@href').extract()
for dist in dists:
url = 'https://sz.lianjia.com'+dist
yield scrapy.Request(url,self.parse_small_dist,dont_filter=True)
再獲取小區(qū)域鏈接,
def parse_small_dist(self,response):
small_dists = response.xpath('//div[@data-role="ershoufang"]/div[2]/a/@href').extract()
for small_dist in small_dists:
url = 'https://sz.lianjia.com' + small_dist
if url not in self.dists_list:
self.dists_list.append(url)
yield scrapy.Request(url,selfs.parse_dist_house_page,dont_filter=True)
因為大區(qū)中的小區(qū)域還有部分重復(fù)了签杈,建了個self.dists_list列表用來排重瘫镇,減少需要爬取的頁面。
獲取小區(qū)域頁碼總數(shù)答姥,
def parse_dist_house_page(self,response):
total_dist_house = int(response.xpath('//h2[@class="total fl"]/span/text()').extract()[0])
if total_dist_house >0:
page_info = response.xpath('//div[@class="page-box house-lst-page-box"]/@page-data').extract()[0]
page_dic = json.loads(page_info)
page_num = page_dic.get('totalPage')
else:
page_num = 0
url = response.url
log_info = '區(qū)域鏈接: '+url+' 區(qū)域二手房總數(shù): '+str(total_dist_house)+' 區(qū)域二手房頁數(shù): '+str(page_num)+'\n'
with open('log.txt','a+') as f:
f.write(log_info)
distinfo = url+','+str(total_dist_house)+','+str(page_num)+'\n'
with open('distinfo.csv','a+') as f:
f.write(distinfo)
if page_num > 0:
for i in range(1, page_num + 1):
url = response.url + 'pg' + str(i) + '/'
yield scrapy.Request(url, callback=self.parse_dist_page, dont_filter=True)
奇了怪了居然有2個小區(qū)域中沒有房源铣除,還的帶個判斷。log.txt用來存些錯誤信息鹦付。distinfo.csv用來存每個小區(qū)域的房源數(shù)尚粘,爬完了再來對下有沒有漏。
獲取小區(qū)域中每一頁中的房源鏈接敲长,
def parse_dist_page(self,response):
urls = response.xpath('//ul[@class="sellListContent"]/li/a/@href').extract()
for url in urls:
yield scrapy.Request(url,callback=self.onsale_page,dont_filter=True)
終于爬到最后一層了郎嫁,獲取每個房源的詳細信息。
def onsale_page(self,response):
item = SzlianjiaItem()
soup = BeautifulSoup(response.text, 'lxml')
title = soup.select('div.title h1')[0].text
price = float(soup.select('span.total')[0].text) if soup.select('span.total') else ''
unitprice = float(soup.select('span.unitPriceValue')[0].text.rstrip('元/平米')) if soup.select(
'span.unitPriceValue') else ''
houseID = soup.select('div.houseRecord span.info')[0].text.rstrip('舉報') if soup.select(
'div.houseRecord span.info') else ''
xiaoqu = soup.select('div.communityName a')[0].text if soup.select('div.communityName a') else ''
infos = [i.text for i in soup.select('div.introContent div.content ul li')]
info = {}
for i in infos:
key = i[:4]
data = i[4:]
info[key] = data
info['標題'] = title
info['總價'] = price
info['單價'] = unitprice
info['鏈家編號'] = houseID
info['小區(qū)'] = xiaoqu
info['房屋鏈接'] = response.url
info['建筑面積'] = float(info['建筑面積'].rstrip('㎡')) if '㎡' in info['建筑面積'] else ''
info['套內(nèi)面積'] = float(info['套內(nèi)面積'].rstrip('㎡')) if '㎡' in info['套內(nèi)面積'] else ''
info['掛牌時間'] = datetime.datetime.strptime(info['掛牌時間'],'%Y-%m-%d') if info['掛牌時間'] != '暫無數(shù)據(jù)' else ''
for key in info.keys():
if info[key] != '暫無數(shù)據(jù)':
item[key] = info[key]
else:
item[key] = ''
yield item
前面幾層都是用xpath解析祈噪,比較簡單泽铛,不需要引進額外的包,我對xpath還不是很熟辑鲤,正好用來練手不過最后一層太多字段了盔腔,想偷個懶,就用更熟練的美麗湯來解析月褥,順便改下某些字段的類型弛随,方面以后處理。
結(jié)果
最后爬下來宁赤,獲取了25800個房源信息撵幽,可是。礁击。。
完美主義害死人啊挚躯!
先這樣了强衡,明天接著改。
后續(xù)計劃
把所有小區(qū)信息爬下來码荔。
把所有已售房屋信息爬下來漩勤。
分析。
買房缩搅!
ヽ(Д*)/.?哈哈