Python爬蟲總結
總的來說,Python爬蟲所做的事情分為兩個部分,1:將網頁的內容全部抓取下來,2:對抓取到的內容和進行解析,得到我們需要的信息。
目前公認比較好用的爬蟲框架為Scrapy,而且直接使用框架比自己使用requests、 beautifulsoup、 re包編寫爬蟲更加方便簡單。
1、關於Scrapy框架
簡介: Scrapy是一個為了爬取網站數據,提取結構性數據而編寫的應用框架。 其最初是為了 頁面抓取 (更確切來說, 網絡抓取 )所設計的, 也可以應用在獲取API所返回的數據(例如 Amazon Associates Web Services ) 或者通用的網絡爬蟲。
官方文檔地址 : http://scrapy-chs.readthedocs.io/zh_CN/1.0/index.html
Scrapy安裝 : pip install Scrapy
創建Scrapy項目 : scrapy startproject scrapyspider(projectname)
該命令創建包涵下列內容的目錄:

這些文件分別是:
- scrapy.cfg: 項目的配置文件。
- scrapyspider/: 該項目的python模塊。之后您將在此加入代碼。
- scrapyspider/items.py: 項目中的item文件。
- scrapyspider/pipelines.py: 項目中的pipelines文件,用來執行保存數據的操作。
- scrapyspider/settings.py: 項目的設置文件。
- scrapyspider/spiders/: 放置爬蟲代碼的目錄。
編寫爬蟲:以爬取豆瓣電影TOP250為例展示一個完整但簡單的Scrapy爬蟲的流程
- 首先,在items.py文件中聲明需要提取的數據,Item 對象是種簡單的容器,保 存了爬取到得數據。 其提供了 類似於詞典(dictionary-like) 的API以及用於聲明可 用字段的簡單語法。許多Scrapy組件使用了Item提供的額外信息: exporter根據 Item聲明的字段來導出 數據、 序列化可以通過Item字段的元數據(metadata) 來 定義、trackref 追蹤Item 實例來幫助尋找內存泄露 (see 使用 trackref 調試內 存泄露) 等等。
- Item使用簡單的class定義語法以及Field對象來聲明。我們打開scrapyspider目錄下的items.py文件寫入下列代碼聲明Item:

為了創建一個爬蟲,首先需要繼承scrapy.Spider類,定義以下三個屬性:
1、name : 用於區別不同的爬蟲,名字必須是唯一的。
2、start_urls: 包含了Spider在啟動時進行爬取的url列表。
3、parse() 是spider的一個函數。 被調用時,每個初始URL完成下載后生成的 Response 對象將會作為唯一的參數傳遞給該函數,然后解析提取數據。
在scrapyspider/spiders目錄下創建douban_spider.py文件,並寫入初步的代碼:
from scrapy import Request
from scrapy.spiders import Spider
from scrapyspider.items import DoubanMovieItem
class DoubanMovieTop250Spider(Spider):
name = 'douban_movie_top250'
headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',}#設置請求頭文件,模擬瀏覽器訪問(涉及反爬機制)
def start_requests(self):#該函數定義需要爬取的初始鏈接並下載網頁內容
url = 'https://movie.douban.com/top250'
yield Request(url, headers=self.headers)
def parse(self, response):
item = DoubanMovieItem()
movies = response.xpath('//ol[@class="grid_view"]/li') #使用xpath對下載到的網頁源碼進行解析
for movie in movies:
item['ranking'] = movie.xpath(
'.//div[@class="pic"]/em/text()').extract()[0]
item['movie_name'] = movie.xpath(
'.//div[@class="hd"]/a/span[1]/text()').extract()[0]
item['score'] = movie.xpath(
'.//div[@class="star"]/span[@class="rating_num"]/text()'
).extract()[0]
item['score_num'] = movie.xpath(
'.//div[@class="star"]/span/text()').re(ur'(\d+)人評價')[0]
yield item
next_url = response.xpath('//span[@class="next"]/a/@href').extract() #解析得到下一頁的鏈接
if next_url:
next_url = 'https://movie.douban.com/top250' + next_url[0]
yield Request(next_url, headers=self.headers) #下載下一頁的網頁內容
運行爬蟲: 在項目文件夾內打開cmd運行下列命令:
此處的douban_movie_top250即為我們剛剛寫的爬蟲的name, 而-o douban.csv是scrapy提供的功能,將item輸出為csv格式的文件,存儲到douban.csv中。
得到數據:

到此我們已經可以解決一般普通網站的抓取任務,普通網站是指網頁源碼之中包含了所有我們想要抓取的內容,但是有的時候一些網站采用了Ajax異步加載的方法,導致以上介紹的方法無法使用。
2、關於抓取Ajax異步加載的網站
Ajax是什么:
AJAX即“Asynchronous Javascript And XML”(異步JavaScript和XML),是指一種創建交互式網頁應用的網頁開發技術。
通過在后台與服務器進行少量數據交換,AJAX 可以使網頁實現異步更新。這意味着可以在不重新加載整個網頁的情況下,對網頁的某部分進行更新。
通過Ajax異步加載的網頁內容在網頁源碼中是沒有的,也就是之前介紹的方法中下載到的response中是解析不到我們想要的內容的。
如何抓取AJAX異步加載頁面:
對於這類網頁,我們一般采用兩種方法:
1、通過抓包找到異步加載請求的真正地址
2、通過PhantomJS等無頭瀏覽器執行JS代碼后再抓取
但是通常采取第一種方法,因為第二種方法使用無頭瀏覽器會大大降低抓取的效率。
異步加載網站抓取示例 :
使用豆瓣電影分類排行榜作為抓取示例,鏈接為
https://movie.douban.com/typerank?type_name=%E5%8A%A8%E4%BD%9C&type=5&interval_id=100:90&action=
電影信息網頁源碼中沒有,並且采用鼠標下拉更新頁面,這時需要我們在需要抓取的頁面打開Chrome的開發者工具,選擇network,實現一次下拉刷新


發現新增了一個get請求,並且響應為JSON格式。觀察JSON的內容,發現正是需要抓取的內容。
抓取內容的問題解決了,接下來處理多頁抓取問題,因為請求為get形式,所以首先進行幾次下拉刷新,觀察請求鏈接的變化,會發現請求的地址中只有start的值在變化,並且每次刷新增加20,其他都不變,所以我們更改這個參數就可以實現翻頁。
由於之前已經在items.py中對需要抓取的數據做了聲明,所以只需要在scraoyspider/spiders目錄下創建一個新的爬蟲文件douban_actions.py,代碼如下:
import re
import json
from scrapy import Request
from scrapy.spiders import Spider
from scrapyspider.items import DoubanMovieItem
class DoubanAJAXSpider(Spider):
name = 'douban_ajax' #設置爬蟲名字為douban_ajax
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 Safari/537.36',
} #設置請求頭文件,模擬瀏覽器訪問(涉及反爬機制)
def start_requests(self):
url = 'https://movie.douban.com/j/chart/top_list?type=5&interval_id=100%3A90&action=&start =0&limit=20'
yield Request(url, headers=self.headers)
def parse(self, response):
datas = json.loads(response.body)#將Json格式數據處理為字典類型
item = DoubanMovieItem()
if datas:
for data in datas:
item['ranking'] = data['rank']
item['movie_name'] = data['title']
item['score'] = data['score']
item['score_num'] = data['vote_count']
yield item
# 如果datas存在數據則對下一頁進行采集
page_num = re.search(r'start=(\d+)', response.url).group(1)
page_num = 'start=' + str(int(page_num)+20)
next_url = re.sub(r'start=\d+', page_num, response.url)
#處理鏈接
yield Request(next_url, headers=self.headers)
#請求下一頁
運行爬蟲 :
scrapy crawl douban_ajax -o douban_movie.csv
然而,很多時候ajax請求都會經過后端鑒權,不能直接構造URL獲取。這時就可以通過PhantomJS、chromedriver等配合Selenium模擬瀏覽器動作,抓取經過js渲染后的頁面。
使用這種方法有時會遇到定位網頁頁面元素定位不准的情況,這時就要注意網頁中的frame標簽,frame標簽有frameset、frame、iframe三種,frameset跟其他普通標簽沒有區別,不會影響到正常的定位,而frame與iframe對selenium定位而言是一樣的,需要進行frame的跳轉。(這兩點暫不展開,在抓取中財網—數據引擎網站時就遇到此類問題)
彩蛋:
兩個提高效率的Chrome插件:
Toggle JavaScript (檢測網頁哪些內容使用了異步加載)
JSON-handle (格式化Json串)
3、關於突破爬蟲反爬機制
目前使用到的反反爬手段主要有三個:
1、在請求之間設置延時,限制請求速度。(使用python time庫)
2、在每次請求時都隨機使用用戶代理User-Agent,為了方便,在scrapy框架中,可以使用fake-useragent這個開源庫。
Github地址:https://github.com/hellysmile/fake-useragent
3、使用高匿代理ip,同樣為了方便,在scrapy框架中編寫爬蟲,建議使用開源庫 scrapy-proxies。
Github地址:https://github.com/aivarsk/scrapy-proxies
參考內容地址:https://zhuanlan.zhihu.com/p/24769534
