把以前寫的爬蟲代碼整理成教程,方便以后查閱,可以爬點感興趣的東西玩一玩。
1.運行環境及安裝:
1.運行環境
默認讀者已經掌握了python2/3的基本操作。
??操作系統:win7
??IDE:Anaconda3 (32-bit)中的jupyter notebook(Anaconda3中對應的是python3,用python2也無妨,推薦用python3)
??用到的python庫:BeautifulSoup(一個可以從HTML或XML中提取數據的python庫),requests(rllib的升級版,打包了全部功能并簡化了使用方法)
??瀏覽器:Google Chrome
2.Anaconda3 安裝
Anaconda是一個用于科學計算的Python發行版,支持 Linux, Mac, Windows系統,提供了包管理與環境管理的功能,可以很方便地解決多版本python并存、切換以及各種第三方包安裝問題。
??登陸Anaconda官網下載相應版本并安裝:https://www.continuum.io/downloads/
??常用的庫numpy,pandas等都集成在了Anaconda里,本教程用的BeautifulSoup也包含在內。
??安裝完成后,點擊開始菜單,找到Anaconda文件夾中的jupyter notebook,打開。
??jupyter notebook是一個在瀏覽器中運行的IDE,訪問本地文件。當然,用其他的IDE也可以,這里推薦用notebook。
??5分鐘可快速入門notebook,簡明教程請移步http://codingpy.com/article/getting-started-with-jupyter-notebook-part-1/。
??開搞!
2.爬取網頁中鏈接對應的網址
我們要爬取的內容為趕集網二手手機交易頁面中每個商品的詳細信息,網址為:http://bj.ganji.com/shouji/a2/。
??我們的思路是這樣的:首先獲得每個商品對應的鏈接,然后進入這個鏈接,爬取商品信息。
1.解析網頁元素
因為我們要獲得圖1中每個商品的鏈接,需要解析網頁元素。因為是入門教程,所以不會涉獵太多HTML的知識。
??對著圖1中第1個商品“蘋果三星華為……”右擊,選擇“檢查”,在瀏覽器右側會彈出圖2所示的窗口:
紅色箭頭指向的那一行表示層級關系,從開始的html字段開始,一直定位到a.ft-tit字段,最終定位到商品所在的網頁源碼的位置,即我們想要找的元素。參考這個層級關系,我們可以自己定位任意想要的元素(編程時會用到)。
??例如,現在要手動定位第1個商品:
??1. 點擊圖2任意空白部分(保證該窗口為當前活動窗口),按下鍵盤上的Ctrl+F,會在圖2中的側邊欄的中間部分彈出一個搜索框,如藍色箭頭所指。
??2. 在搜索框中輸入紅色箭頭所指的層級字段,中間以“>”相連,即:html>body>#wrapper>div>div>dl>dd.feature>div.ft-db>ul>li.js-item>a.ft-tit
。第1個商品所在字段自動加上了底紋。
??3. 搜索框右側的“1 of 70”表示與此定位同級的位置一共有70個,現在是第1個,也就我們要定位的第1個商品。可以通過搜索框右側的上/下箭頭選擇同級的定位,比如下一個商品為“五動全城……”,可見我們定位的字段正是我們想要的。
??顯然,在底紋字段中,我們想要爬取的正是下面這個鏈接:
“http://bj.ganji.com/shouji/29130462136655x.htm
2.提取網頁元素
首先,引入我們要用到的python庫:
from bs4 import BeautifulSoup
import requests
爬取鏈接:
#目標網址
url = 'http://bj.ganji.com/shouji/a2/'
#請求訪問目標網址
wb_data = requests.get(url)
#用lxml解析目標網址
soup = BeautifulSoup(wb_data.text,'lxml')
#定位到我們要爬取的信息,返回一個列表(注意每個“>”前后都有空格)
links = soup.select('html > body > #wrapper > div > div > dl > dd.feature > div.ft-db > ul > li.js-item > a.ft-tit')
#在每個商品的源碼中,篩選出我們想要的鏈接,存放到列表link_list 中
link_list = []
for each_link in links:
link_list.append(each_link.get('href'))
在上面的代碼中,我們用requests的get方法去訪問目標網址,返回數據到wb_data中,然后用BeautifulSoup方法用lxml來解析wb_data,以便可以提取我們想要的信息。select方法返回所有滿足定位要求的源碼段到一個列表中,一共是70個,對應70個商品。最后對列表中的每個元素應用get方法,獲取我們要想的字段。對于如下一般結構:
<a href="xxx" target="xxx" class="xxx">華為 三星……</a>
- 如果要獲得href,target和class等屬性字段的值,可以用get方法。如each_link.get('href'),each_link.get('target')和each_link.get('class')分別以字符串的形式返回href,target和class的值。
- 如果要獲得< a >和< /a >之間的文本,可用get_text方法即each_link.get_text(),返回字符串“華為 三星……”。
這里我們想要href的值,即鏈接,故應用get方法,存放到列表link_list中。查看一下link_list中的元素,如圖3。
??我們成功了獲取了每個商品的鏈接,接下來就要依次訪問這些鏈接來爬取商品信息。
3.爬取商品詳細信息
1.爬取單個商品信息
以第1個商品為例,我們要爬取的內容為標題、發布日期、價格和地點,見圖4。
??和上面的過程一樣,對標題右擊,檢查,得到標題的定位(見圖5)。然后重復同樣的過程,得到其他信息的定位。
??爬取這些信息:
url = 'http://bj.ganji.com/shouji/29130462136655x.htm'
wb_data = requests.get(url)
soup = BeautifulSoup(wb_data.text,'lxml')
title = soup.select('h1.title-name')[0].get_text()
price = soup.select('i.f22.fc-orange.f-type')[0].get_text()
date = soup.select('i.pr-5')[0].get_text()
areas = soup.select('ul.det-infor > li > a')
area = ''
for i in areas:
area += i.get_text()+'-'
area = area[:-1]
data = {
'標題':title,
'日期':date.strip().split('\xa0')[0],
'價格':price,
'地點':area
}
在上面的代碼中,我們訪問第1個商品的鏈接,解析網頁,爬取了我們想要的4個信息,然后把這些信息放到一個字典里,這樣每個商品的信息都可以用一個字典來表示。
??注意到,在前3個select方法中,我們只寫了1個字段;在第4個select方法中,我們只寫了3個字段。這是因為,在這個網頁中,只寫這幾個字段就足以唯一定位出我們想要的信息的位置,無需寫完整。(讀者可自行驗證)當然,你想寫全了也無妨。
??打印上面代碼中的data:
{'標題': '蘋果7 7P 分期付款可回收手機以舊換新 - 4200元', '價格': '4200', '地點': ' 北京-海淀'}
這樣,單個商品的信息就存放在了一個字典中。
2.爬取所有商品詳細信息
好了,現在你已經會爬取單個商品了,那爬取所有商品也不在話下了。在上面的代碼中加個循環就能爬取所有商品信息了:
#爬取列表中的每個鏈接對應的商品信息
for each_link in link_list:
wb_data = requests.get(each_link)
soup = BeautifulSoup(wb_data.text,'lxml')
#篩選標題、價格、日期、位置
title = soup.select('h1.title-name')[0].get_text()
price = soup.select('i.f22.fc-orange.f-type')[0].get_text()
date = soup.select('i.pr-5')[0].get_text()
areas = soup.select('ul.det-infor > li > a')
area = ''
for i in areas:
area += i.get_text()+'-'
area = area[:-1]
data = {
'標題':title,
'日期':date.strip().split('\xa0')[0],
'價格':price,
'地點':area
}
print (data)
對于代碼中細節的處理,讀者可自行嘗試。
??輸出如下(只顯示前6條商品信息):
{'標題': '‘五動全城’ 分期付款零首付 全新二手手機 多種購機方式!!! - 3950元', '日期': '04月26日', '價格': '3950', '地點': ' 北京-海淀'}
{'標題': '北京實體店買手機《就分期》分期付款最低0首付 - 4488元', '日期': '03月25日', '價格': '4488', '地點': ' 北京'}
{'標題': '蘋果iphoe7 7plus 0利息三星手機分期付款 審核快 通過率高【平價二手】【以舊換新】 - 4188元', '日期': '02月16日', '價格': '4188', '地點': ' 北京'}
{'標題': '蘋果7 7P 分期付款可回收手機以舊換新 - 4200元', '日期': '04月25日', '價格': '4200', '地點': ' 北京-海淀'}
{'標題': '有用分期 0首付起( 全系列手機) 當場拿機 優惠288禮包 - 4599元', '日期': '03月07日', '價格': '4599', '地點': ' 北京-朝陽'}
{'標題': '《有分期》大型手機專賣店手機分期支持0首付 - 4288元', '日期': '04月26日', '價格': '4288', '地點': ' 北京-朝陽'}
至此為止,我們基本掌握了理想條件下爬取網頁的操作。但以上我們只是爬取了二手手機交易頁面這一頁的所有商品,注意到下面其實還有很多頁,如圖6。
??下面我們就來爬取趕集網上所有二手手機的信息。
3.爬取趕集網所有二手手機信息
往下面翻頁,會發現不同頁的網址是遵循一定規律的。第1頁到第3頁的網址如下:
http://bj.ganji.com/shouji/a2/
http://bj.ganji.com/shouji/a2o2/
http://bj.ganji.com/shouji/a2o3/
第1頁的網址也可以寫成
http://bj.ganji.com/shouji/a2o1/
也就是說,第N頁的網址就是
http://bj.ganji.com/shouji/a2oN/
根據這個規律,我們就能通過編程來爬取所有商品了。只需要把爬取商品鏈接的代碼稍作修改即可:
url_base = 'http://bj.ganji.com/shouji/a2o'
N = 2 #要爬取的頁數
link_list = []
for i in range(N):
url = url_base + str(i+1)
wb_data = requests.get(url)
soup = BeautifulSoup(wb_data.text,'lxml')
links = soup.select('a.ft-tit')
for each_link in links:
link_list.append(each_link.get('href'))
4.最后的話
一般來說,網站都有反爬蟲技術,在如此短的時間內爬取那么多信息,網站會認為你是爬蟲。關于“反反爬蟲”也有很多方法,最簡單也是最笨的一個辦法就是延時,即每爬取幾條信息就延時幾秒,讓自己的爬蟲看起來是一個正常上網的人。可用python自帶的time模塊來完成,讀者可自行嘗試。
??像趕集網、58同城、豆瓣還是比較好爬的,數據比較規整。讀者可以去一些小網站試試,可能需要你對數據作更多細節上的處理。
好了,現在你已經學會爬蟲的基本操作了,可以去其他網站爬取一些感興趣的東西下載下來,比如說煎蛋網