作者:京東物流 田禹
1 網路爬蟲
網路爬蟲:是一種按照一定的規則,自動地抓取萬維網資訊的程式或者腳本,
網路爬蟲相關技術和框架繁多,針對場景的不同可以選擇不同的網路爬蟲技術,
2 Scrapy框架(Python)
2.1. Scrapy架構
2.1.1. 系統架構
2.1.2. 執行流程
總結爬蟲開發程序,簡化爬蟲執行流程如下圖所示:
爬蟲運行主要流程如下:
(1) Scrapy啟動Spider后加載Spaider的start_url,生成request物件;
(2) 經過middleware完善request物件(添加IP代理、User-Agent);
(3) Downloader物件按照request物件下載頁面;
(4) 將response結果傳遞給spider的parser方法決議;
(5) spider獲取資料封裝為item物件傳遞給pipline,決議的request物件將回傳呼度器進行新一輪的資料抓取;
2.2. 框架核心檔案介紹
2.2.1. scrapy.cfg
scrapy.cfg是scrapy框架的入口檔案,settings節點指定爬蟲的配置資訊,deploy節點用于指定scrapyd服務的部署路徑,
| [settings]
default = sfCrawler.settings
[deploy]
url =http://localhost:6800/
project = jdCrawler
|
2.2.2. settings.py
settings主要用于配置爬蟲啟動資訊,包括:并發執行緒數量、使用的middleware、items等資訊;也可以作為系統中的全域的組態檔使用,
注:目前主要增加了redis、資料庫連接等相關配置資訊,
2.2.3. middlewares.py
middleware定義了多種介面,分別在爬蟲加載、輸入、輸出、請求、請求例外等情況進行呼叫,
注:目前主要用戶是為爬蟲增加User-Agent資訊和IP代理資訊等,
2.2.4. pipelines.py
用于定義處理資料的Pipline物件,scrapy框架可以在settings.py檔案中配置多個pipline物件,處理資料的個程序將按照settings.py配置的優先級的順序順次執行,
注:系統中產生的每個item物件,將經過settings.py配置的所有pipline物件,
2.2.5. items.py
用于定義不同種資料型別的資料字典,每個屬性都是Field型別;
2.2.6. spider目錄
用于存放Spider子類定義,scrapy啟動爬蟲程序中將按照spider類中name屬性進行加載和呼叫,
2.3. 爬蟲功能擴展說明
2.3.1. user_agents_middleware.py
通過procces_request方法,為request物件添加hearder資訊,隨機模擬多種瀏覽器的User-Agent資訊進行網路請求,
2.3.2. proxy_server.py
通過procces_request方法,為reques物件添加網路代理資訊,隨機模擬多IP呼叫,
2.3.3. db_connetion_pool.py
檔案位置
db_manager/db_connetion_pool.py,檔案定義了基礎的資料連接池,方便系統各環節操作資料庫,
2.3.4. redis_connention_pool.py
檔案位置db_manager/ redis_connention_pool.py,檔案定義了基礎的Redis連接池,方便系統各環節操作Redis快取,
2.3.5. scrapy_redis包
scrapy_redis包是對scrapy框架的擴展,采用Redis作為請求佇列,存盤爬蟲任務資訊,
spiders.py檔案:定義分布式RedisSpider類,通過覆寫Spider類start_requests()方法的方式,從Redis快取中獲取初始請求串列資訊,其中RedisSpider子類需要為redis_key賦值,
pipelines.py檔案:定義了一種簡單的資料存盤方式,可以直接將item物件序列化后保存到Redis快取中,
dupefilter.py檔案:定義資料去重類,采用Redis快取的方式,已經保存的資料將添加到過濾佇列中,
queue.py檔案:定義幾種不同的入隊和出隊順序的佇列,佇列采用Redis存盤,
2.4. 微博爬蟲開發示例
2.4.1. 查找爬蟲入口
2.4.1.1. 站點分析
網站一般會分為Web端和M端兩種,兩種站點在設計和架構上會有較大的差別,通常情況下Web端會比較成熟,User-Agent檢查、強制Cookie、登錄跳轉等限制,抓取難度相對較大,回傳結果以HTML內容為主;M端站點通常采用前后端分離設計,大多提供獨立的資料介面,所以站點分析程序中優先查找M端站點入口,微博Web端及M端效果如圖所示:
微博Web端地址:https://weibo.com/,頁面顯示效果如下圖所示:
注:圖片來源于微博PC端截圖
微博M端地址:https://m.weibo.cn/?jumpfrom=weibocom,頁面顯示效果如下圖所示:
注:圖片來源于微博M端截圖
2.4.1.2. HTML原始碼分析
Web端站點和M端站點回傳結果都是HTML格式,部分站點為了提升頁面渲染速度,或者為了增加代碼分析難度,通過動態JavaScrip執行等方式,動態生成HTML頁面,網路爬蟲缺少JS執行和渲染程序,很難獲取真實的資料,微博Web端站點HTML代碼片段如下所示:
腳本中的正文內容:
M端站點HTML內容:
M端HTML內容中并未出現頁面中的關鍵資訊,可以判定為前后端分離的設計方式,通過Chrome瀏覽器開發模式,能夠查看所有請求資訊,通過請求的型別和回傳結果,基本可以確定介面地址,查找程序如下圖所示:
注:圖片來源于微博M端截圖
(1) 打開Chrome開發者工具,重繪當前頁面;
(2) 修改請求型別為XHR,篩選Ajax請求;
(3) 查看所有請求資訊,忽略沒有回傳結果的介面;
(4) 在介面回傳結果中查找頁面中相關內容,
2.4.1.3. 介面分析
介面分析主要包括:請求地址分析、請求方式、引數串列、回傳結果等,
請求地址、請求方式和引數串列可以根據Chrome開發人員工具中的網路請求Header資訊獲取,請求資訊如下圖所示:
上圖中介面地址采用的是GET方式請求,請求地址是unicode編碼,引數內容可以查看Query String Parameters串列查看請求引數,效果如下圖所示:
請求結果分析主要分析資料結構的特點,查找與正文內容相同的資料結構,同時要檢查所有結果是否與正文內容一致,避免特殊回傳結果影響資料決議程序,
2.4.1.4. 介面驗證
介面驗證一般需要兩個步驟:
(1)用瀏覽器(最好是新開瀏覽器,如Chrome的隱身模式)模擬請求程序,在地址欄中輸入帶有引數的請求地址查看回傳結果,
(2)采用Postman等工具模擬瀏覽器請求程序,主要模擬非Get方式的網路請求,同樣也可以驗證站點是否強制使用Cookie和User-Agent資訊等,
2.4.2. 定義資料結構
爬蟲資料結構定義主要結合業務需求和資料抓取的結果進行設計,微博資料主要用戶國內的輿情系統,所以在開發程序中將相關站點的資料統一定義為OpinionItem型別,在不同站點的資料保存程序中,按照OpinionItem資料結構的特點裝配資料,在items.py檔案中定義輿情資料結構如下所示:
class OpinionItem(Item):
rid = Field()
pid = Field()
response_content = Field() # 介面回傳的全部資訊
published_at = Field() # 發布時間
title = Field() # 標題
description = Field() # 描述
thumbnail_url = Field() # 縮略圖
channel_title = Field() # 頻道名稱
viewCount = Field() # 觀看數
repostsCount = Field() # 轉發數
likeCount = Field() # 點贊數
dislikeCount = Field() # 不喜歡數量
commentCount = Field() # 評論數
linked_url = Field() # 鏈接
updateTime = Field() # 更新時間
author = Field() # 作者
channelId = Field() # 渠道ID
mediaType = Field() # 媒體型別
crawl_time = Field() # 抓取時間
type = Field() # 資訊型別:1 主貼 2 主貼的評論
2.4.3. 爬蟲開發
微博爬蟲采用分布式RedisSpider作為父類,爬蟲定義如下所示:
class weibo_list(RedisSpider):
name = 'weibo'
allowed_domains = ['weibo.cn']
redis_key = 'spider:weibo:list:start_urls'
def parse(self, response):
a = json.loads(response.body)
b = a['data']['cards']
for j in range(len(b)):
bb = b[j]
try:
for c in bb['card_group']:
try:
d = c['mblog']
link = 'https://m.weibo.cn/api/comments/show?id={}'.format(d['mid'])
# yield scrapy.Request(url=link, callback=self.parse_detail)
# 內容決議代碼片段
opinion['mediaType'] = 'weibo'
opinion['type'] = '1'
opinion['crawl_time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())
yield opinion
except Exception as e:
print(e)
continue
except Exception as e:
print(e)
continue
代碼決議:
代碼行1:定義weibo_list類,繼承RedisSpider類;
代碼行2:定義爬蟲名稱,爬蟲啟動時使用;
代碼行3:增加允許訪問的地址域名串列;
代碼行4:定義微博開始請求地址的redis key;
代碼行6:定義爬蟲的決議方法,爬蟲下載頁面后默認呼叫parser方法;
代碼行7~21:將下載結果內容決議后裝配到item物件中;
代碼行22:通過yield關鍵字,生成Python特有的生成器物件,呼叫者可以通過生成器物件遍歷所有結果,
2.4.4. 資料存盤
資料存盤主要通過定義Pipline實作類,將爬蟲決議的資料進行保存,微博資料需要增加進行情感分析的加工程序,開發程序中首先將微博資料保存到Redis服務中,通過后續的情感分析決議服務獲取、加工,并保存到資料庫中,資料保存代碼如下所示:
class ShunfengPipeline(object):
def process_item(self, item, spider):
if isinstance(item, OpinionItem):
try:
print('===========Weibo查詢結果============')
key = 'spider:opinion:data'
dupe = 'spider:opinion:dupefilter'
attr_list = []
for k, v in item.items():
if isinstance(v, str):
v = v.replace('\'', '\\\'')
attr_list.append("%s:'%s'" % (k, v))
data = ",".join(attr_list)
data = "{%s}" % data
# 按照資料來源、型別和唯一id作為去重標識
single_key = ''.join([item['mediaType'], item['type'], item['rid']])
if ReidsPool().rconn.execute_command('SADD', dupe, single_key) != 0:
ReidsPool().rconn.execute_command('RPUSH', key, data)
except Exception as e:
print(e)
pass
return item
關鍵代碼說明:
代碼行1:定義Pipline類;
代碼行2:定義process_item方法,用于接收資料;
代碼行3:按照Item型別分別處理;
代碼行4~17:Item物件拼裝為JSON字串;
代碼行18~21:對資料進行去重校驗,并將資料保存到redis佇列中;
代碼行26:回傳item物件供其他Pipline操作;
Pipline定義完成后,需要在工程中的settings.py檔案中進行配置,配置內容如下所示:
| # 配置專案管道
ITEM_PIPELINES = {
"sfCrawler.pipelines.JdcrawlerPipeline": 401,
"sfCrawler.pipelines_manage.mysql_pipelines.MySqlPipeline": 402,
"sfCrawler.pipelines_manage.shunfeng_pipelines.ShunfengPipeline": 403,
}
|
爬蟲入門地址:
https://scrapy-chs.readthedocs.io/zh_CN/0.24/intro/tutorial.html
3 WebMagic框架(Java)
3.1 前言
總結Scrapy使用程序中存在的問題,以及爬蟲系統后期上線需求考慮,采用Java語言進行爬蟲的設計與開發,具體原因如下:
(1)上線基礎環境依賴:需要使用線上Clover、JimDB、MySQL等基礎環境;
(2)可擴展性強:以現有框架為基礎,二次封裝Request請求物件,實作通用網路爬蟲開發,提供易擴展的地址生成、網頁決議介面,
(3)集中部署:通過部署通用爬蟲方式,抓取所有支持站點的爬蟲,解決Scrapy框架一站點一部署問題,
(4)反-反爬蟲:部分站點針對Scrapy框架請求特點,實施反爬蟲策略(如:天貓),拒絕所有爬蟲請求,WebMagic模擬瀏覽器請求,不受該爬蟲限制,
3.2 WebMagic概述
(內容來源:https://webmagic.io/docs/zh/posts/ch1-overview/architecture.html)
3.2.1 總體架構
WebMagic的結構分為Downloader、PageProcessor、Scheduler、Pipeline四大組件,并由Spider將它們彼此組織起來,這四大組件對應爬蟲生命周期中的下載、處理、管理和持久化等功能,WebMagic的設計參考了Scapy,但是實作方式更Java化一些,
而Spider則將這幾個組件組織起來,讓它們可以互相互動,流程化的執行,可以認為Spider是一個大的容器,它也是WebMagic邏輯的核心,
WebMagic總體架構圖如下:
3.1.2 WebMagic的四個組件
3.1.2.1 Downloader
Downloader負責從互聯網上下載頁面,以便后續處理,WebMagic默認使用了Apache HttpClient作為下載工具,
3.1.2.2 PageProcessor
PageProcessor負責決議頁面,抽取有用資訊,以及發現新的鏈接,WebMagic使用Jsoup作為HTML決議工具,并基于其開發了決議XPath的工具Xsoup,
在這四個組件中,PageProcessor對于每個站點每個頁面都不一樣,是需要使用者定制的部分,
3.1.2.3 Scheduler
Scheduler負責管理待抓取的URL,以及一些去重的作業,WebMagic默認提供了JDK的記憶體佇列來管理URL,并用集合來進行去重,也支持使用Redis進行分布式管理,
除非專案有一些特殊的分布式需求,否則無需自己定制Scheduler,
3.1.2.4 Pipeline
Pipeline負責抽取結果的處理,包括計算、持久化到檔案、資料庫等,WebMagic默認提供了“輸出到控制臺”和“保存到檔案”兩種結果處理方案,
Pipeline定義了結果保存的方式,如果你要保存到指定資料庫,則需要撰寫對應的Pipeline,對于一類需求一般只需撰寫一個Pipeline,
3.1.3 用于資料流轉的物件
3.1.3.1 Request
Request是對URL地址的一層封裝,一個Request對應一個URL地址,
它是PageProcessor與Downloader互動的載體,也是PageProcessor控制Downloader唯一方式,
除了URL本身外,它還包含一個Key-Value結構的欄位extra,你可以在extra中保存一些特殊的屬性,然后在其他地方讀取,以完成不同的功能,例如附加上一個頁面的一些資訊等,
3.1.3.2 Page
Page代表了從Downloader下載到的一個頁面——可能是HTML,也可能是JSON或者其他文本格式的內容,
Page是WebMagic抽取程序的核心物件,它提供一些方法可供抽取、結果保存等,在第四章的例子中,我們會詳細介紹它的使用,
3.1.3.3 ResultItems
ResultItems相當于一個Map,它保存PageProcessor處理的結果,供Pipeline使用,它的API與Map很類似,值得注意的是它有一個欄位skip,若設定為true,則不應被Pipeline處理,
3.1.4 控制爬蟲運轉的引擎--Spider
Spider是WebMagic內部流程的核心,Downloader、PageProcessor、Scheduler、Pipeline都是Spider的一個屬性,這些屬性是可以自由設定的,通過設定這個屬性可以實作不同的功能,Spider也是WebMagic操作的入口,它封裝了爬蟲的創建、啟動、停止、多執行緒等功能,下面是一個設定各個組件,并且設定多執行緒和啟動的例子,詳細的Spider設定請看第四章——爬蟲的配置、啟動和終止,
public static void main(String[] args) {
Spider.create(new GithubRepoPageProcessor())
//從https://github.com/code4craft開始抓
.addUrl("https://github.com/code4craft")
//設定Scheduler,使用Redis來管理URL佇列
.setScheduler(new RedisScheduler("localhost"))
//設定Pipeline,將結果以json方式保存到檔案
.addPipeline(new JsonFilePipeline("D:\\data\\webmagic"))
//開啟5個執行緒同時執行
.thread(5)
//啟動爬蟲
.run();
}
3.3 通用爬蟲分析及設計
3.2.1 通用爬蟲功能分析
(1)單個應用同時支持多個站點的資料抓取;
(2)支持集群部署;
(3)容易擴展;
(4)支持重復抓取;
(5)支持定時抓取;
(6)具備大資料分析擴展能力;
(7)降低大資料分析集成復雜度,提高代碼復用性;
(8)支持線上部署;
3.2.2 通用爬蟲設計
通用爬蟲設計思路是在WebMagic基礎上,將Scheduler、Processor、Pipeline進行定制,設計如下圖所示:
設計程序中按照爬蟲開發的特點,將爬蟲實作程序拆分為兩個環節:生成請求和內容決議,
(1)生成請求(UrlParser):按照不同站點的請求地址及引數特點(如:Get/Post請求方式,URL引數拼接等)及業務需要(如:使用國內代理還是國外代理),按照站點引數拼裝成為通用的Request請求物件,指導Downloader進行網頁下載,
(2)內容決議(HtmlParser):按照決議網頁內容的特點,通過XPATH、JSON等方式對頁面內容進行提取程序,每個內容決議器只針對相同頁面內容進行決議,當內容中包含深度頁面抓取的請求時,由UrlParser生成新的請求物件并回傳給調度器,
3.2.3 任務調度設計
為了實作爬蟲的分布式,將Scheduler功能進行榷訓,實作程序增加Clover、Worker、Redis環節,Clover負責定時調度Worker生成默認請求物件(一般為檢索功能、首頁重復抓取任務等),將生成的請求物件添加到Redis佇列中,Scheduler只負責從Redis佇列中獲取請求地址即可,
3.2.4 Processor設計
Processor用于決議Downloader下載的網頁內容,為了充分利用服務器網路和計算資源,設計之初考慮能夠將網頁下載和內容決議拆分到不同服務中進行處理,避免爬蟲節點CPU時間過長造成網路帶寬的浪費,所以,設計程序中按照爬蟲內部決議和外部平臺集成決議兩種方式進行設計,
(1)爬蟲內部決議:即下載內容直接由Processor完成頁面決議程序,生成Items物件和深度Request物件,為了簡化對多個站點內容的決議程序,Processor主要負責資料結構的組織和HtmlParser的呼叫,通過Spring IOC的方式實作多個站點HtmlParser集成程序,
(2)外部平臺集成:能夠將爬蟲抓取內容通過MQ等方式,實作其他平臺或服務的對接程序,實作程序中可以將抓取的網頁內容組織成為文本型別,通過Pipline方式將資料發送到JMQ中,按照JMQ方式實作與其他服務和平臺的對接程序,其他服務可以復用HtmlParser和UrlParser完成內容決議程序,
3.2.5 Pipline設計
Pipline主要用于資料的轉儲,為了適用Processor的兩種方案,設計MySQLPipeline和JMQPipeline兩種實作方式,
3.4 通用爬蟲實作
3.4.1 Request
WebMagic提供的Request類能夠滿足網路請求的基本需求,包括URL地址、請求方式、Cookies、Headers等資訊,為了實作通用的網路請求,對現有請求物件進行業務擴展,增加是否過濾、過濾token、請求頭型別(PC/APP/WAP)、代理IP國別分類、失敗重試次數等,擴展內容如下:
/**
* 站點
*/
private String site;
/**
* 型別
*/
private String type;
/**
* 是否過濾 default:TRUE
*/
private Boolean filter = Boolean.TRUE;
/**
* 唯一token,URL地址去重使用
*/
private String token;
/**
* 決議器名稱
*/
private String htmlParserName;
/**
* 是否填充Header資訊
*/
private Integer headerType = HeaderTypeEnums.NONE.getValue();
/**
* 國別型別,用于區分使用代理型別
* 默認為國內
*/
private Integer nationalType = NationalityEnums.CN.getValue();
/**
* 頁面最大抓取深度,用于限制串列頁深度鉆取深度,按照訪問次數依次遞減
* <p>Default: 1</p>
* <p> depth = depth - 1</p>
*/
private Integer depth = 1;
/**
* 失敗重試次數
*/
private Integer failedRetryTimes;
3.4.2 UrlParser & HtmlParser
3.4.2.1 UrlParser實作
UrlParser主要用與按照引數串列生成固定的請求物件,為了簡化Workder的開發程序,在介面中增加了生成初始化請求的方法,
/**
* URL地址轉換
* @author liwanfeng1
*/
public interface UrlParser {
/**
* 獲取定時任務初始化請求物件串列
* @return 請求物件串列
*/
List<SeparateRequest> getStartRequest();
/**
* 按照引數生成Request請求物件
* @param params
* @return
*/
SeparateRequest parse(Map<String, Object> params);
}
3.4.2.2 HtmlParser實作
HtmlParser主要是將Downloader內容進行決議,并回傳data串列及深度抓取的Request物件,實作如下:
/**
* HTML代碼轉換
* @author liwanfeng1
*/
public interface HtmlParser {
/**
* HTML格式化
* @param html 抓取的網頁內容
* @param request 網路請求的Request物件
* @return 資料決議結果
*/
HtmlDataEntity parse(String html, SeparateRequest request);
}
/**
* @author liwanfeng1
* @param <T> 資料型別
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class HtmlDataEntity<T extends Serializable> {
private List<T> data;
private List<SeparateRequest> requests;
/**
* 添加資料物件
* @param obj 資料物件
*/
public void addData(T obj){
if(data =https://www.cnblogs.com/Jcloud/p/= null) {
data = new ArrayList<>();
}
data.add(obj);
}
/**
* 添加Request物件
* @param request 請求物件
*/
public void addRequest(SeparateRequest request) {
if(requests == null) {
requests = new ArrayList<>();
}
requests.add(request);
}
}
3.4.3 Worker
Workder的作用是定時生成請求物件,結合UrlParser介面的應用,設計統一的WorkerTask實作類,代碼如下:
/**
*
* @author liwanfeng1
*/
@Slf4j
@Data
public class CommonTask extends AbstractScheduleTaskProcess<SeparateRequest> {
private UrlParser urlParser;
private SpiderQueue spiderQueue;
/**
* 獲取任務串列
* @param taskServerParam 引數串列
* @param i 編號
* @return 任務串列
*/
@Override
protected List<SeparateRequest> selectTasks(TaskServerParam taskServerParam, int i) {
return urlParser.getStartRequest();
}
/**
* 執行任務串列,組織Google API請求地址,添加到YouTube串列爬蟲的佇列中
* @param list 任務串列
*/
@Override
protected void executeTasks(List<SeparateRequest> list) {
spiderQueue.push(list);
}
}
添加Worker配置如下:
<!-- Facebook start -->
<bean id="facebookTask" >
<property name="urlParser">
<bean />
</property>
<property name="spiderQueue" ref="jimDbQueue"/>
</bean>
<jsf:provider id="facebookTaskProcess"
interface="com.jd.clover.schedule.IScheduleTaskProcess" ref="facebookTask"
server="jsf" alias="woker:facebookTask">
</jsf:provider>
<!-- Facebook end -->
3.4.4 Scheduler
調度主要用于推送、拉取最新任務,以及輔助的推送重復驗證、佇列長度獲取等方法,介面設計如下:
/**
* 爬蟲任務佇列
* @author liwanfeng
*/
public interface SpiderQueue {
/**
* 添加佇列
* @param params 爬蟲地址串列
*/
default void push(List<SeparateRequest> params) {
if (params == null || params.isEmpty()) {
return;
}
params.forEach(this::push);
}
/**
* 將SeparaterRequest地址添加到Redis佇列中
* @param separateRequest SeparaterRequest地址
*/
void push(SeparateRequest separateRequest);
/**
* 彈出佇列
* @return SeparaterRequest物件
*/
Request poll();
/**
* 檢查separateRequest是否重復
* @param separateRequest 封裝的爬蟲url地址
* @return 是否重復
*/
boolean isDuplicate(SeparateRequest separateRequest);
/**
* 默認URL地址生成Token<br/>
* 建議不同的URLParser按照站點地址的特點,生成較短的token
* 默認采用site、type、url地址進行下劃線分割
* @param separateRequest 封裝的爬蟲url地址
*/
default String generalToken(SeparateRequest separateRequest) {
return separateRequest.getSite() + "_" + separateRequest.getType() + "_" + separateRequest.getUrl();
}
/**
* 獲取佇列總長度
* @return 佇列長度
*/
Long getQueueLength();
}
4 瀏覽器呼叫爬蟲(Python)
瀏覽器呼叫爬蟲主要借助Selenium與ChromeDriver技術,通過本地化瀏覽器呼叫方式加載并決議頁面內容,實作資料抓取,瀏覽器呼叫主要解決復雜站點的資料抓取,部分站點通過流程拆分、邏輯封裝、代碼拆分、代碼混淆等方式增加代碼分析的復雜度,結合請求拆分、資料加密、客戶端行為分析等方式進行反爬操作,使爬蟲程式無法模擬客戶端請求程序向服務端發起請求,
該種方式主要應用于順豐快遞單號查詢程序,訂單查詢采用騰訊滑動驗證碼插件進行人機驗證,基本流程如下圖所示:
首先配置ChromeDriver組件到作業系統中,組件下載地址:
https://chromedriver.storage.googleapis.com/index.html?path=2.44/,將檔案保存到系統環境變數“PATH”中指定的任意路徑下,建議:C:\Windows\system32目錄下,
組件添加驗證:啟用命令列視窗->任意路徑運行“ChromeDriver.exe”,程式會以服務形式運行,
爬蟲實作程序如下:
(1)啟動瀏覽器:為了實作爬蟲的并發,需要通過引數方式對瀏覽器進行優化設定;
啟動瀏覽器
def getChromeDriver(index):
options = webdriver.ChromeOptions()
options.add_argument("--incognito") # 無痕模式
options.add_argument("--disable-infobars") # 關閉選單欄
options.add_argument("--reset-variation-state") # 重置校驗狀態
options.add_argument("--process-per-tab") # 獨立每個tab頁為單獨行程
options.add_argument("--disable-plugins") # 禁用所有插件
options.add_argument("headless") # 隱藏視窗
proxy = getProxy()
if proxy is not None:
options.add_argument("--proxy-server==http://%s:%s" % (proxy["host"], proxy["port"])) # 添加代理
return webdriver.Chrome(chrome_options=options)
(2)加載頁面:呼叫瀏覽器訪問指定地址頁面,并等待頁面加載完成;
driver.get('http://www.sf-express.com/cn/sc/dynamic_function/waybill/#search/bill-number/' + bill_number)
driver.implicitly_wait(20) #最長等待20秒加載時間
(3)切換Frame:驗證碼采用IFrame方式加載到當前頁面,接下來需要對頁面元素進行操作,需要將driver切換到iframe中;
driver.switch_to.frame("tcaptcha_popup")
driver.implicitly_wait(10) #等待切換完成,其中iframe加載可能有延遲
(4)滑動模塊:滑動頁面中的滑塊到指定位置,實作驗證程序;
滑動驗證碼操作程序如下圖所示:
滑動模塊執行距離在240像素前后,整個滑動程序取樣14個,模擬拋物線執行程序控制滑動速度,將這個滑動程序分為20次移動(避免每次采樣結果相同),分析如下圖所示:
代碼如下:
# 隨機生成滑塊拖動軌跡
def randomMouseTrace():
trace = MouseTrace()
trace.x = [20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 9, 9, 8, 8, 7, 7, 6, 6, 5, 5]
trace.y = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
trace.time = [0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1, 0.1]
return trace
# 拖動滑塊
def dragBar(driver, action):
dragger = driver.find_element_by_id("tcaptcha_drag_button")
action.click_and_hold(dragger).perform() # 滑鼠左鍵按下不放
action.reset_actions()
trace = randomMouseTrace()
for index in range(trace.length()):
action.move_by_offset(trace.x[index], trace.y[index]).perform() # 移動一個位移
action.reset_actions()
time.sleep(trace.time[index]) # 等待停頓時間
action.release().perform() # 滑鼠左鍵松開
action.reset_actions()
return driver.find_element_by_id("tcaptcha_note").text == ""
(4)資料決議及存盤:資料決議程序主要是按照id或class進行元素定位獲取文本內容,將結果插入到資料庫即完成資料抓取程序,
(5)其他:采用Python的threading進行多執行緒呼叫,將訂單編號保存到Redis中實作分布式任務獲取程序,每執行一次將POP一個訂單編號,
待改進:
(1)模塊滑動速度和時間固定,可以進行隨機優化;
(2)未識別滑塊釋放位置,目前采用滑塊更新的方式重試,存在一定的錯誤率;
(3)如果不切換代理IP,需要對瀏覽器啟動進行優化,減少啟動次數,提升抓取速度;
5 gocolly框架(Go)
多執行緒并發執行是Go語言的優勢之一,Go語言通過“協程”實作并發操作,當執行的協程發生I/O阻塞時,會由專門協程進行阻塞任務的管理,對服務器資源依賴更少,抓取效率也會有所提高,
(以下內容轉自:https://www.jianshu.com/p/23d4ecb8428f)
5.1 概述
gocolly是用go實作的網路爬蟲框架gocolly快速優雅,在單核上每秒可以發起1K以上請求;以回呼函式的形式提供了一組介面,可以實作任意型別的爬蟲;依賴goquery庫可以像jquery一樣選擇web元素,
gocolly的官方網站是http://go-colly.org/,提供了詳細的檔案和示例代碼,
5.2 安裝配置
安裝
go get -u github.com/gocolly/colly/
引入包
import "github.com/gocolly/colly"
5.3 流程說明
5.3.1 使用流程
使用流程主要是說明使用colly抓取資料前的準備作業
-
初始化Collector物件, Collector物件是colly的全域句柄
-
設定全域設定,全域設定主要是設定colly 句柄的代理設定等
-
注冊抓取回呼函式, 主要是用于在抓取資料后在資料處理的各個流程提取資料以及出發其他操作
-
設定輔助工具,如抓取鏈接的存放佇列,資料清洗佇列等
-
注冊抓取鏈接
-
啟動程式開始抓取
5.3.2 抓取流程
每次抓取資料流程中的各個節點都會嘗試觸發用戶注冊的抓取回呼函式,以完成提取資料等需求, 抓取流程如下,
-
根據鏈接每次準備抓取資料前呼叫 注冊的OnRequest做每次抓取前的預處理作業
-
當抓取資料失敗時會呼叫OnError做錯誤處理
-
抓取到資料后呼叫OnResponse,做剛抓到資料時的處理作業
-
然后分析抓取到的資料會根據頁面上的dom節點觸發OnHTML回呼進行資料分析
-
資料分析完畢后會呼叫OnScraped函式進行每次抓取后的收尾作業
5.4. 輔助介面
colly也提供了部分輔助介面,協助完成資料抓取分析流程, 以下列舉一部分主要的支持,
-
queue 用于存放等待抓取的鏈接
-
proxy 用于代理發起抓取源
-
thread 支持多攜程并發處理
-
filter 支持對特殊鏈接進行過濾
-
depth 可以設定抓取深度控制抓取
5.5. 實體
更多可以參考原始碼鏈接中的例子(https://github.com/gocolly/colly/tree/master/_examples)
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/551589.html
標籤:Python
上一篇:使用python查看五黃及羅猴
下一篇:返回列表
