編譯環境:python v3.5.0, mac osx 10.11.4
<big>python爬蟲基礎知識: Python爬蟲學習-基礎爬取</big>
了解數據庫 MongoDB
- 數據庫是儲存數據的地方,可以將如下的字典結構插入到MongoDB的存儲單元中。
data = {
'name':peter
'id':123
...
} # 需存儲的文件 -
數據庫的構成:可以將其類比于excel表格進行理解
client = pymongo.MongoClient('localhost',27017) # 將python與mongodb進行連接,'localhost'表示本地環境, 207017是端口號
walden = client['walden'] # 創建一個庫文件
以上代碼可以類似于創建一個excel文件,文件名為walden
sheet_tab = walden['sheet_tab'] # 在庫文件中建立一個頁面名叫 sheet_tab
以上代碼可以類似于創建excel文件中的一個表單
- 數據庫的基本操作:
- 向頁邊中插入數據:
sheet_tab.insert_one(data)
其中data為python中的字典結構,可有如下代碼生成:
path = './walden.txt' # 輸入數據的路徑,為讀取數據做準備
with open(path,'r') as f: # 打開文件,為只讀模式
lines = f.readlines()
for index,line in enumerate(lines): # 逐個生成字典元素
data = {
'index':index,
'line' :line,
'words':len(line.split())
}
sheet_tab.insert_one(data) # 將字典元素插入庫文件頁面中
- 向頁邊中插入數據:
- 篩選數據庫中的數據(基礎篩選)
sheet_tab.find({'words':{'$lt':5}} # 選擇字典中關鍵字words對應值小于5的所有字典元素
# $lt/$lte/$gt/$gte/$ne,依次等價于</<=/>/>=/!=。(l表示less g表示greater e表示equal n表示not )
基礎實戰(篩選房源)
篩選小豬短租網站前三頁信息儲存到MongoDB中,篩選出價格大于等于500元房源,并打印出來。房源信息具體要求如下:
- <big>實戰源碼</big> (下載地址xiaozhu.py)
# -- coding: utf-8 --
import requests, time, pymongo
from bs4 import BeautifulSoup
def gender_info(soup): # 獲取性別信息
gender = 'female' if soup.find_all('div','div.member_ico1') else 'male'
return gender
def get_info(url): # 獲取所需的房源信息
wb_data = requests.get(url) # 向服務器請求頁面
wb_data.encoding ='utf-8' # 標明編碼為utf-8,以免出現解碼錯誤
soup = BeautifulSoup(wb_data.text,'lxml') # 以lxml方式對頁面進行解析
title = soup.select('h4 em')[0].text
address = soup.select('span.pr5')[0].text
price = int(soup.select('div.day_l span')[0].text)
img = soup.select('#curBigImage')[0].get('src')
hostPic = soup.select('#floatRightBox > div.js_box.clearfix > div.member_pic > a > img')[0].get('src')
hostName = soup.select('#floatRightBox > div.js_box.clearfix > div.w_240 > h6 > a')[0].text
hostGender = gender_info(soup)
data = {
'title' : title,
'address': address,
'price' : price,
'img' :img,
'hostPic' : hostPic,
'hostName' : hostName,
'hostGender' : hostGender
}
print('get_info Done')
return data
def get_list_url(pageURL): # 獲取頁面中所有詳細房源的url
listUrl = []
wb_data = requests.get(pageURL)
wb_data.encoding = 'utf-8'
soup = BeautifulSoup(wb_data.text,'lxml')
pageList = soup.select('div.result_btm_con.lodgeunitname')
for i in pageList:
listUrl.append(i.get('detailurl'))
print('get_list_url Done')
return listUrl
def get_info_by_page(startPage, endPage, baseURL,database): # 獲取整個頁面的信息
for i in range(startPage,endPage+1):
url = baseURL.format(i)
listUrl = get_list_url(url)
for j in listUrl:
time.sleep(4)
dataInfo = get_info(j) # 獲取每個頁面的信息
database.insert_one(dataInfo) # 將信息插入到指定的頁面中
print('input to database Done')
client = pymongo.MongoClient('localhost',27017) # 連接mongodb
xiaozhu = client['xiaozhu'] # 創建一個名叫xiaozhu的庫文件
home_info = xiaozhu['home_info'] # 創建一個home_info的頁面
pageBaseUrl = 'http://bj.xiaozhu.com/search-duanzufang-p{}-0/' # 構造共同url連接
get_info_by_page(1,3,pageBaseUrl,home_info) # 調用函數爬取信息并將信息儲存到mongodb中
for info in home_info.find({'price':{'$gte':500}}): # 打印大于等于500的房源信息
print(info) - <big>結果展示</big>
mongoDB中的儲存結果(部分截圖)
爬取工作分析流程
<big>1. </big>觀察頁面特征,保證爬蟲程序的通用性,即:發現邊界條件和局限性。
例:爬取趕集網-北京二手市場的所有類目中屬于<big>個人</big>的商品信息。
-
觀察的到頁面(url)變動的信息
- 發現頁面變動邊界條件
-
當把頁面設定到150頁時,我們發現返回的頁面是任意四件商品的信息。因此,我們要據此,判斷我們所爬取的頁面是否已經到頭。避免重復的信息加入到我們的數據庫中。
-
并且通過觀察發現網站這一返回操作,我們發現正常頁面中有列表鏈接可以點擊,而由于頁面超出范圍返回的隨機商品信息頁面沒有。
- 因此我們可以用BeautifulSoup庫中的find方法實現這個操作。
soup.find('ul', 'pageLink') #找到返回TRUE,沒有返回FALSE
-
當把頁面設定到150頁時,我們發現返回的頁面是任意四件商品的信息。因此,我們要據此,判斷我們所爬取的頁面是否已經到頭。避免重復的信息加入到我們的數據庫中。
- 一般這種交易網站,當商品賣出后,商品有關信息頁面將會被刪除,所以我們爬取的過程中,可能將有商品被賣出,當我們向服務器進行請求該商品詳情界面時會出現404 not found。我們可以通過status_code的方法對頁面進行判斷。
wb_data.status_code == 404 # 判斷商品是否已被賣出,賣出則返回TRUE,沒有則返回FALSE
<big>2. </big>設計工作流程,保證輸出效率和穩定性。
-
分步進行:先獲取channel_list(所有頻道分類的URL),保證爬取的穩定性。若是爬取類目信息,與爬取商品信息同步進行的話,當程序出現錯誤時,我們則什么信息也不能得到。所以分步進行可以降低風險。(圖中分類項目下的所有商品詳情鏈接)
多進程爬取: 可以利用multiprocess庫中的pool函數,進行多進程爬取,這樣可以提高爬取的效率。
關于進程與線程:
可以理解成多個人完成吃飯這個工作的效率:
單線程單進程:只有一個餐桌,一個人在一個餐桌上吃飯,每個人依次進行。
單線程多進程:有多個餐桌,每個餐座上只有一個人在吃飯。
單進程多線程: 只有一個餐桌,一個餐桌上可以坐多個人。
多進程多線程:多個餐座,一個餐桌上可以坐多個人。對項目進行監測:
我們可以設計一個檢測函數,隔一段時間匯報所抓取信息的數量,對項目進程進行掌控。
import timeframe page_parsing
import url_list
while True:
print(url_list.find().count())
time.sleep(5)-
設計斷點續傳程序:
由于在我們抓取的過程中可能會遇到網絡問題,導致程序終止,而我們不希望重新開始抓取,而是在中斷后的地方繼續進行抓取。
- 數據庫中建立兩個頁面存放詳情商品鏈接(從這一點也可以看出分步抓取的重要性)。一個存放需要抓取的(url_list1)一個存放已經抓取網商品信息的 (url_list2)。
- 當中斷后繼續抓取時,url_list1-url_list2就是剩下帶抓取的商品信息頁面。
db_urls = [item['url'] for item in url_list.find()] # 用列表解析式裝入所有要爬取的鏈接
index_urls = [item['url'] for item in item_info.find()] # 所引出詳情信息數據庫中所有的現存的 url 字段
x = set(db_urls) # 轉換成集合的數據結構
y = set(index_urls)rest_of_urls = x-y # 剩下的url
爬取結果以及源碼(按設計步驟展示)
- 分類鏈接列表channel_list
- 分類詳情頁列表get_url_from
- 商品詳情列表(單個事例)get_iterms_from
-
整體運行界面
**All source code **: JacobKam-GitHub