編譯環(huán)境:python v3.5.0, mac osx 10.11.4
<big>python爬蟲基礎(chǔ)知識: Python爬蟲學(xué)習(xí)-基礎(chǔ)爬取</big>
了解數(shù)據(jù)庫 MongoDB
- 數(shù)據(jù)庫是儲存數(shù)據(jù)的地方,可以將如下的字典結(jié)構(gòu)插入到MongoDB的存儲單元中视卢。
data = {
'name':peter
'id':123
...
} # 需存儲的文件 -
數(shù)據(jù)庫的構(gòu)成:可以將其類比于excel表格進行理解
client = pymongo.MongoClient('localhost',27017) # 將python與mongodb進行連接腐晾,'localhost'表示本地環(huán)境, 207017是端口號
walden = client['walden'] # 創(chuàng)建一個庫文件
以上代碼可以類似于創(chuàng)建一個excel文件袄秩,文件名為walden
sheet_tab = walden['sheet_tab'] # 在庫文件中建立一個頁面名叫 sheet_tab
以上代碼可以類似于創(chuàng)建excel文件中的一個表單
- 數(shù)據(jù)庫的基本操作:
- 向頁邊中插入數(shù)據(jù):
sheet_tab.insert_one(data)
其中data為python中的字典結(jié)構(gòu)砸琅,可有如下代碼生成:
path = './walden.txt' # 輸入數(shù)據(jù)的路徑兑燥,為讀取數(shù)據(jù)做準(zhǔn)備
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) # 將字典元素插入庫文件頁面中
- 向頁邊中插入數(shù)據(jù):
- 篩選數(shù)據(jù)庫中的數(shù)據(jù)(基礎(chǔ)篩選)
sheet_tab.find({'words':{'$lt':5}} # 選擇字典中關(guān)鍵字words對應(yīng)值小于5的所有字典元素
# $lt/$lte/$gt/$gte/$ne茶敏,依次等價于</<=/>/>=/!=玉工。(l表示less g表示greater e表示equal n表示not )
基礎(chǔ)實戰(zhàn)(篩選房源)
篩選小豬短租網(wǎng)站前三頁信息儲存到MongoDB中,篩選出價格大于等于500元房源汁胆,并打印出來梭姓。房源信息具體要求如下:
- <big>實戰(zhàn)源碼</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) # 向服務(wù)器請求頁面
wb_data.encoding ='utf-8' # 標(biāo)明編碼為utf-8,以免出現(xiàn)解碼錯誤
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): # 獲取頁面中所有詳細(xì)房源的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'] # 創(chuàng)建一個名叫xiaozhu的庫文件
home_info = xiaozhu['home_info'] # 創(chuàng)建一個home_info的頁面
pageBaseUrl = 'http://bj.xiaozhu.com/search-duanzufang-p{}-0/' # 構(gòu)造共同url連接
get_info_by_page(1,3,pageBaseUrl,home_info) # 調(diào)用函數(shù)爬取信息并將信息儲存到mongodb中
for info in home_info.find({'price':{'$gte':500}}): # 打印大于等于500的房源信息
print(info) - <big>結(jié)果展示</big>
mongoDB中的儲存結(jié)果(部分截圖)
爬取工作分析流程
<big>1. </big>觀察頁面特征,保證爬蟲程序的通用性嫩码,即:發(fā)現(xiàn)邊界條件和局限性誉尖。
例:爬取趕集網(wǎng)-北京二手市場的所有類目中屬于<big>個人</big>的商品信息官辽。
-
觀察的到頁面(url)變動的信息
- 發(fā)現(xiàn)頁面變動邊界條件
-
當(dāng)把頁面設(shè)定到150頁時郁岩,我們發(fā)現(xiàn)返回的頁面是任意四件商品的信息。因此脏答,我們要據(jù)此丢间,判斷我們所爬取的頁面是否已經(jīng)到頭探熔。避免重復(fù)的信息加入到我們的數(shù)據(jù)庫中。
-
并且通過觀察發(fā)現(xiàn)網(wǎng)站這一返回操作烘挫,我們發(fā)現(xiàn)正常頁面中有列表鏈接可以點擊诀艰,而由于頁面超出范圍返回的隨機商品信息頁面沒有。
- 因此我們可以用BeautifulSoup庫中的find方法實現(xiàn)這個操作。
soup.find('ul', 'pageLink') #找到返回TRUE其垄,沒有返回FALSE
-
當(dāng)把頁面設(shè)定到150頁時郁岩,我們發(fā)現(xiàn)返回的頁面是任意四件商品的信息。因此脏答,我們要據(jù)此丢间,判斷我們所爬取的頁面是否已經(jīng)到頭探熔。避免重復(fù)的信息加入到我們的數(shù)據(jù)庫中。
- 一般這種交易網(wǎng)站苛蒲,當(dāng)商品賣出后,商品有關(guān)信息頁面將會被刪除绿满,所以我們爬取的過程中臂外,可能將有商品被賣出,當(dāng)我們向服務(wù)器進行請求該商品詳情界面時會出現(xiàn)404 not found喇颁。我們可以通過status_code的方法對頁面進行判斷漏健。
wb_data.status_code == 404 # 判斷商品是否已被賣出,賣出則返回TRUE无牵,沒有則返回FALSE
<big>2. </big>設(shè)計工作流程漾肮,保證輸出效率和穩(wěn)定性。
-
分步進行:先獲取channel_list(所有頻道分類的URL)茎毁,保證爬取的穩(wěn)定性克懊。若是爬取類目信息,與爬取商品信息同步進行的話七蜘,當(dāng)程序出現(xiàn)錯誤時谭溉,我們則什么信息也不能得到。所以分步進行可以降低風(fēng)險橡卤。(圖中分類項目下的所有商品詳情鏈接)
多進程爬劝缒睢: 可以利用multiprocess庫中的pool函數(shù),進行多進程爬取碧库,這樣可以提高爬取的效率柜与。
關(guān)于進程與線程:
可以理解成多個人完成吃飯這個工作的效率:
單線程單進程:只有一個餐桌,一個人在一個餐桌上吃飯嵌灰,每個人依次進行弄匕。
單線程多進程:有多個餐桌,每個餐座上只有一個人在吃飯沽瞭。
單進程多線程: 只有一個餐桌迁匠,一個餐桌上可以坐多個人。
多進程多線程:多個餐座,一個餐桌上可以坐多個人驹溃。對項目進行監(jiān)測:
我們可以設(shè)計一個檢測函數(shù)城丧,隔一段時間匯報所抓取信息的數(shù)量,對項目進程進行掌控豌鹤。
import timeframe page_parsing
import url_list
while True:
print(url_list.find().count())
time.sleep(5)-
設(shè)計斷點續(xù)傳程序:
由于在我們抓取的過程中可能會遇到網(wǎng)絡(luò)問題亡哄,導(dǎo)致程序終止,而我們不希望重新開始抓取傍药,而是在中斷后的地方繼續(xù)進行抓取磺平。
- 數(shù)據(jù)庫中建立兩個頁面存放詳情商品鏈接(從這一點也可以看出分步抓取的重要性)魂仍。一個存放需要抓取的(url_list1)一個存放已經(jīng)抓取網(wǎng)商品信息的 (url_list2)拐辽。
- 當(dāng)中斷后繼續(xù)抓取時拣挪,url_list1-url_list2就是剩下帶抓取的商品信息頁面。
db_urls = [item['url'] for item in url_list.find()] # 用列表解析式裝入所有要爬取的鏈接
index_urls = [item['url'] for item in item_info.find()] # 所引出詳情信息數(shù)據(jù)庫中所有的現(xiàn)存的 url 字段
x = set(db_urls) # 轉(zhuǎn)換成集合的數(shù)據(jù)結(jié)構(gòu)
y = set(index_urls)rest_of_urls = x-y # 剩下的url
爬取結(jié)果以及源碼(按設(shè)計步驟展示)
- 分類鏈接列表channel_list
- 分類詳情頁列表get_url_from
- 商品詳情列表(單個事例)get_iterms_from
-
整體運行界面
**All source code **: JacobKam-GitHub