為了分析深圳市所有長租、短租公寓的資訊,爬取了某租房公寓深圳區域所有在租公寓資訊,以下記錄了爬取過程以及爬取過程中遇到的問題:
爬取程式碼:
1 import requests 2 from requests.exceptions import RequestException 3 from pyquery import PyQuery as pq 4 from bs4 import BeautifulSoup 5 import pymongo 6 from config import * 7 from multiprocessing import Pool 8 9 client = pymongo.MongoClient(MONGO_URL) # 申明連線物件 10 db = client[MONGO_DB] # 申明資料庫 11 12 def get_one_page_html(url): # 獲取網站每一頁的html 13 headers = { 14 "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) " 15 "Chrome/85.0.4183.121 Safari/537.36" 16 } 17 try: 18 response = requests.get(url, headers=headers) 19 if response.status_code == 200: 20 return response.text 21 else: 22 return None 23 except RequestException: 24 return None 25 26 27 def get_room_url(html): # 獲取當前頁面上所有room_info的url 28 doc = pq(html) 29 room_urls = doc('.r_lbx .r_lbx_cen .r_lbx_cena a').items() 30 return room_urls 31 32 33 def parser_room_page(room_html): 34 soup = BeautifulSoup(room_html, 'lxml') 35 title = soup.h1.text 36 price = soup.find('div', {'class': 'room-price-sale'}).text[:-3] 37 x = soup.find_all('div', {'class': 'room-list'}) 38 area = x[0].text[7:-11] # 面積 39 bianhao = x[1].text[4:] 40 house_type = x[2].text.strip()[3:7] # 戶型 41 floor = x[5].text[4:-2] # 樓層 42 location1 = x[6].find_all('a')[0].text # 分割槽 43 location2 = x[6].find_all('a')[1].text 44 location3 = x[6].find_all('a')[2].text 45 subway = x[7].text[4:] 46 addition = soup.find_all('div', {'class': 'room-title'})[0].text 47 yield { 48 'title': title, 49 'price': price, 50 'area': area, 51 'bianhao': bianhao, 52 'house_type': house_type, 53 'floor': floor, 54 'location1': location1, 55 'location2': location2, 56 'location3': location3, 57 'subway': subway, 58 'addition': addition 59 } 60 61 62 def save_to_mongo(result): 63 if db[MONGO_TABLE].insert_one(result): 64 print('儲存到mongodb成功', result) 65 return True 66 return False 67 68 69 def main(page): 70 url = 'http://www.xxxxx.com/room/sz?page=' + str(page) # url就不粘啦,嘻嘻 71 html = get_one_page_html(url) 72 room_urls = get_room_url(html) 73 for room_url in room_urls: 74 room_url_href = room_url.attr('href') 75 room_html = get_one_page_html(room_url_href) 76 if room_html is None: # 非常重要,否則room_html為None時會報錯 77 pass 78 else: 79 results = parser_room_page(room_html) 80 for result in results: 81 save_to_mongo(result) 82 83 if __name__ == '__main__': 84 pool = Pool() # 使用多程式提高爬取效率 85 pool.map(main, [i for i in range(1, 258)])
在寫爬取程式碼過程中遇到了兩個問題:
(一)在get_room_url(html)函式中,開始是想直接return每個租房資訊的room_url,但是return不同於print,函式執行到return時就會結束該函式,這樣就只能返回每頁第一個租房room_url。解決辦法是:return 包含每頁所有room_url的generator生成器,在main函式中用for迴圈遍歷,再從每個room_url中獲取href,傳入到get_one_page_html(room_url_href)中進行解析。
(二)沒有寫第76行的if語句,我預設get_one_page_html(room_url_href)返回的room_html不為空,因此出現multiprocessing.pool.RemoteTraceback報錯:
上圖中顯示markup為None情況下報錯,點選藍色"F:\ProgramFiles\anaconda3\lib\site-packages\bs4\__init__.py"發現markup為room_html,即部分room_html出現None情況。要解決這個問題,必須讓程式碼跳過room_html is None的情況,因此新增 if 語句解決了這個問題。
最終成功爬取某租房公寓深圳市258頁共4755條租房資訊,為下一步進行資料分析做準備。
其中單條資訊: