日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 >

Python爬虫开发从入门到实战

發(fā)布時(shí)間:2024/3/13 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Python爬虫开发从入门到实战 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

Python爬蟲開發(fā)從入門到實(shí)戰(zhàn)(微課版)


第1章 緒論

爬蟲的主要目的是獲取網(wǎng)頁內(nèi)容并解析。只要能達(dá)到這個(gè)目的,用什么方法都沒有問題。

關(guān)于獲取網(wǎng)頁,本書主要介紹了Python的兩個(gè)第三方模塊,一個(gè)是requests,另一個(gè)是爬蟲框架Scrapy。

關(guān)于解析網(wǎng)頁內(nèi)容,本書主要介紹了3種方式——正則表達(dá)式、XPath和BeautifulSoup。兩種網(wǎng)頁獲取方式和3種網(wǎng)頁解析方式可以自由搭配,隨意使用。


第2章 Python基礎(chǔ)

知識(shí)點(diǎn)

  • Python開發(fā)環(huán)境的搭建。
  • Python的基本知識(shí)、數(shù)據(jù)類型。
  • Python的條件語句和循環(huán)語句。
  • Python函數(shù)的定義和使用。
  • 基于Python的面向?qū)ο缶幊檀a。

第3章 正則表達(dá)式與文件操作

知識(shí)點(diǎn)

  • 正則表達(dá)式的基本符號(hào)。
  • 如何在Python中使用正則表達(dá)式。
  • 正則表達(dá)式的提取技巧。
  • Python讀寫文本文件和CSV文件。

第4章 簡(jiǎn)單的網(wǎng)頁爬蟲開發(fā)

知識(shí)點(diǎn)

  • requests的安裝和使用。
  • 多線程爬蟲的開發(fā)。
  • 爬蟲的常見算法。

多線程爬蟲的開發(fā)

在掌握了requests與正則表達(dá)式以后,就可以開始實(shí)戰(zhàn)爬取一些簡(jiǎn)單的網(wǎng)址了。

但是,此時(shí)的爬蟲只有一個(gè)進(jìn)程、一個(gè)線程,因此稱為單線程爬蟲。單線程爬蟲每次只訪問一個(gè)頁面,不能充分利用計(jì)算機(jī)的網(wǎng)絡(luò)帶寬。一個(gè)頁面最多也就幾百KB,所以爬蟲在爬取一個(gè)頁面的時(shí)候,多出來的網(wǎng)速和從發(fā)起請(qǐng)求到得到源代碼中間的時(shí)間都被浪費(fèi)了。

如果可以讓爬蟲同時(shí)訪問10個(gè)頁面,就相當(dāng)于爬取速度提高了10倍。為了達(dá)到這個(gè)目的,就需要使用多線程技術(shù)了。

微觀上的單線程,在宏觀上就像同時(shí)在做幾件事。這種機(jī)制在I/O(Input/Output,輸入/輸出)密集型的操作上影響不大,但是在CPU計(jì)算密集型的操作上面,由于只能使用CPU的一個(gè)核,就會(huì)對(duì)性能產(chǎn)生非常大的影響。所以涉及計(jì)算密集型的程序,就需要使用多進(jìn)程,Python的多進(jìn)程不受GIL的影響。

由于爬蟲是I/O密集型的操作,特別是在請(qǐng)求網(wǎng)頁源代碼的時(shí)候,如果使用單線程來開發(fā),會(huì)浪費(fèi)大量的時(shí)間來等待網(wǎng)頁返回,所以把多線程技術(shù)應(yīng)用到爬蟲中,可以大大提高爬蟲的運(yùn)行效率。

多進(jìn)程庫(multiprocessing)

multiprocessing本身是Python的多進(jìn)程庫,用來處理與多進(jìn)程相關(guān)的操作。但是由于進(jìn)程與進(jìn)程之間不能直接共享內(nèi)存和堆棧資源,而且啟動(dòng)新的進(jìn)程開銷也比線程大得多,因此使用多線程來爬取比使用多進(jìn)程有更多的優(yōu)勢(shì)。multiprocessing下面有一個(gè)dummy模塊,它可以讓Python的線程使用multiprocessing的各種方法。

dummy下面有一個(gè)Pool類,它用來實(shí)現(xiàn)線程池。這個(gè)線程池有一個(gè)map()方法,可以讓線程池里面的所有線程都“同時(shí)”執(zhí)行一個(gè)函數(shù)。

from multiprocessing.dummy import Pool as ThreadPool# 使用map實(shí)現(xiàn)多線程爬蟲 pool = ThreadPool(4) pool.map(crawler_func, data_list) pool.close() pool.join()

常見搜索算法

  • DFS
  • BFS

在爬蟲開發(fā)的過程中,應(yīng)該選擇深度優(yōu)先還是廣度優(yōu)先呢?這就需要根據(jù)被爬取的數(shù)據(jù)來進(jìn)行選擇了。

小結(jié)

本章講解了requests的安裝和使用,以及如何使用Python的多進(jìn)程庫multiprocessing來實(shí)現(xiàn)多線程爬蟲。


第5章 高性能HTML內(nèi)容解析

知識(shí)點(diǎn)

  • HTML基礎(chǔ)結(jié)構(gòu)。
  • 使用XPath從HTML源代碼中提取有用信息。
  • 使用Beautiful Soup4從HTML源代碼中提取有用信息。

Beautiful Soup4

Beautiful Soup4(BS4)是Python的一個(gè)第三方庫,用來從HTML和XML中提取數(shù)據(jù)。

pip install beautifulsoup4

小結(jié)

從網(wǎng)頁中提取需要的信息,是爬蟲開發(fā)中最重要但卻最基本的操作。只有掌握并能自由運(yùn)用正則表達(dá)式、XPath與Beautiful Soup4從網(wǎng)頁中提取信息,爬蟲的學(xué)習(xí)才算是入門。

XPath是一門查詢語言,它由C語言開發(fā)而來,因此速度非常快。但是XPath需要經(jīng)過一段時(shí)間的練習(xí)才能靈活應(yīng)用。

Beautiful Soup4是一個(gè)從網(wǎng)頁中提取數(shù)據(jù)的工具,它入門很容易,功能很強(qiáng)大,但是由于是基于Python開發(fā)的,因此速度比XPath要慢。讀者可以自行選擇喜歡的一項(xiàng)來作為自己主要的數(shù)據(jù)提取方式。本書選擇使用XPath,所以后面的內(nèi)容都會(huì)以XPath來進(jìn)行講解。


第6章 Python與數(shù)據(jù)庫

數(shù)據(jù)庫

本章將會(huì)講解MongoDB和Redis這兩個(gè)數(shù)據(jù)庫。其中MongoDB用來保存大量數(shù)據(jù),Redis用于作為緩存和隊(duì)列保存臨時(shí)數(shù)據(jù)。

知識(shí)點(diǎn)

  • MongoDB與Redis的安裝。
  • MongoDB的增刪改查操作。
  • Redis的列表與集合的操作。

在Mac OS下安裝MongoDB

brew update brew install mongodb #啟動(dòng)MongoDB mongod --config /usr/local/etc/mongod.conf

圖形化管理工具—RoboMongo

RoboMongo是一個(gè)跨平臺(tái)的MongoDB管理工具,可以在圖形界面中查詢或者修改MongoDB。

數(shù)據(jù)在MongoDB中是按照“庫(Database)”—“集合(Collections)”—“文檔(Document)”的層級(jí)關(guān)系來存儲(chǔ)的。如果使用Python的數(shù)據(jù)結(jié)構(gòu)來做類比的話,文檔相當(dāng)于一個(gè)字典,集合相當(dāng)于一個(gè)包含了很多字典的列表,庫相當(dāng)于一個(gè)大字典,大字典里面的每一個(gè)鍵值對(duì)都對(duì)應(yīng)了一個(gè)集合,Key為集合的名字,Value就是一個(gè)集合。

PyMongo的安裝

PyMongo模塊是Python對(duì)MongoDB操作的接口包,能夠?qū)崿F(xiàn)對(duì)MongoDB的增刪改查及排序等操作。

pip install pymongo

PyMongo的使用

(1)使用PyMongo初始化數(shù)據(jù)庫

要使用PyMongo操作MongoDB,首先需要初始化數(shù)據(jù)庫連接。如果MongoDB運(yùn)行在本地計(jì)算機(jī)上,而且也沒有修改端口或者添加用戶名及密碼,那么初始化MongoClient的實(shí)例的時(shí)候就不需要帶參數(shù),直接寫為:

from pymongo import MongoClient client = MongoClient()

如果MongoDB是運(yùn)行在其他服務(wù)器上面的,那么就需要使用“URI(Uniform Resource Identifier,統(tǒng)一資源標(biāo)志符)”來指定連接地址。MongoDB URI的格式為:

mongodb://用戶名:密碼@服務(wù)器IP或域名:端口

PyMongo初始化數(shù)據(jù)庫與集合有兩種方式。

# 方式1: from pymongo import MongoClient client = MongoClient() database= client.Chapter6 collection = database.spider # 需要注意,使用方式1的時(shí)候,代碼中的“Chapter6”和“spider”都不是變量名,它們直接就是庫的名字和集合的名字。# 方式2: from pymongo import MongoClient client = MongoClient() database = client['Chapter6'] collection = database['spider'] # 使用方式2時(shí),在方括號(hào)中指定庫名和集合名。這種情況下,方括號(hào)里除了直接寫普通的字符串以外,還可以寫一個(gè)變量。

默認(rèn)情況下,MongoDB只允許本機(jī)訪問數(shù)據(jù)庫。這是因?yàn)镸ongoDB默認(rèn)沒有訪問密碼,出于安全性的考慮,不允許外網(wǎng)訪問。

如果需要從外網(wǎng)訪問數(shù)據(jù)庫,那么需要修改安裝MongoDB時(shí)用到的配置文件mongod.conf。

(2)插入數(shù)據(jù)

MongoDB的插入操作非常簡(jiǎn)單。用到的方法為insert(參數(shù)),插入的參數(shù)就是Python的字典。插入一條數(shù)據(jù)的代碼如下。

from pymongo import MongoClient client = MongoClient() database = client['Chapter6'] collection = database['spider'] data = {'id': 123, 'name': 'kingname', 'age': 20, 'salary': 999999} collection.insert(data)# MongoDB會(huì)自動(dòng)添加一列“_id”,這一列里面的數(shù)據(jù)叫作ObjectId,ObjectId是在數(shù)據(jù)被插入MongoDB的瞬間,通過一定的算法計(jì)算出來的。因此,_id這一列就代表了數(shù)據(jù)插入的時(shí)間,它不重復(fù),而且始終遞增。通過一定的算法,可以把ObjectId反向恢復(fù)為時(shí)間。

將多個(gè)字典放入列表中,并將列表作為insert()方法的參數(shù),即可實(shí)現(xiàn)批量插入數(shù)據(jù),代碼如下。

from pymongo import MongoClient client = MongoClient() database = client['Chapter6'] collection = database['spider'] more_data = [{'id': 2, 'name': '張三', 'age': 10, 'salary': 0},{'id': 3, 'name': '李四', 'age': 30, 'salary': -100},{'id': 4, 'name': '王五', 'age': 40, 'salary': 1000},{'id': 5, 'name': '外國(guó)人', 'age': 50, 'salary': '未知'}, ] collection.insert(more_data)

(3)普通查找

MongoDB的查找功能對(duì)應(yīng)的方法是:

find(查詢條件, 返回字段) find_one(查詢條件,返回字段)普通查詢方法有以下3種寫法。 content = collection.find() content = collection.find({'age': 29}) content = collection.find({'age': 29}, {'_id': 0, 'name': 1, 'salary': 1})

(4)邏輯查詢

PyMongo也支持大于、小于、大于等于、小于等于、等于、不等于這類邏輯查詢。

collection.find({'age': {'$gt': 29}}) #查詢所有age > 29的記錄 collection.find({'age': {'$gte': 29, '$lte': 40}}) #查詢29 ≤ age ≤ 40的記錄 collection.find({'salary': {'$ne: 29}}) #查詢所有salary不等于29的記錄

(5)對(duì)查詢結(jié)果排序

# MongoDB支持對(duì)查詢到的結(jié)果進(jìn)行排序。排序的方法為sort()。它的格式為: handler.find().sort('列名', 1-1)# 查詢一般和find()配合在一起使用。例如: collection.find({'age': {'$gte': 29, '$lte': 40}}).sort('age', -1) collection.find({'age': {'$gte': 29, '$lte': 40}}).sort('age', 1)

(6)更新記錄

更新可使用update_one()和update_many()方法。它們的格式為:

collection.update_one(參數(shù)1, 參數(shù)2) collection.update_many(參數(shù)1, 參數(shù)2)

(7)刪除記錄

刪除可使用delete_one()和delete_many()方法。它們的格式為:

collection.delete_one(參數(shù)) collection.delete_many(參數(shù))

(8)對(duì)查詢結(jié)果去重

去重使用distinct()方法,其格式為:

collection.distinct('列名')

設(shè)計(jì)一個(gè)開關(guān)

思考一個(gè)問題:如何設(shè)計(jì)一個(gè)開關(guān),實(shí)現(xiàn)在不結(jié)束程序進(jìn)程的情況下,從全世界任何一個(gè)有網(wǎng)絡(luò)的地方既能隨時(shí)暫停程序,又能隨時(shí)恢復(fù)程序的運(yùn)行。

最簡(jiǎn)單的方法就是用數(shù)據(jù)庫來實(shí)現(xiàn)。在能被程序和控制者訪問的服務(wù)器中創(chuàng)建一個(gè)數(shù)據(jù)庫,數(shù)據(jù)庫名為“Switch_DB”。數(shù)據(jù)庫里面創(chuàng)建一個(gè)集合“Switch”,這個(gè)集合里面只有一個(gè)記錄,就是“Status”,它只有兩個(gè)值,“On”和“Off”,

在Mac OS下安裝Redis

brew update brew install redis #運(yùn)行Redis redis-server /usr/local/etc/redis.conf

Redis交互環(huán)境的使用

redis-cli

常見操作

keys *可以查看當(dāng)前有多少的“Key”。

在爬蟲開發(fā)的過程中主要會(huì)用到Redis的列表與集合

(1)列表

Redis的列表是一個(gè)可讀可寫的雙向隊(duì)列

lpush key value1 value2 value 3…

如果想查看一個(gè)列表的長(zhǎng)度,可使用關(guān)鍵字為“l(fā)len”。這個(gè)關(guān)鍵字的第1個(gè)“l(fā)”對(duì)應(yīng)的是英文“l(fā)ist”(列表)的首字母。

如果不刪除列表中的數(shù)據(jù),又要把數(shù)據(jù)讀出來,就需要使用關(guān)鍵字“l(fā)range”,這里的“l(fā)”對(duì)應(yīng)的是英文“l(fā)ist”的首字母。”lrange”的使用格式為:

lrange key start end # 其中,start為起始位置,end為結(jié)束位置。例如: lrange chapter_6 0 3# 需要特別注意的是,在Python中,切片是左閉右開區(qū)間,例如,test[0:3]表示讀列表的第0、1、2個(gè)共3個(gè)值。但是lrange的參數(shù)是一個(gè)閉區(qū)間,包括開始,也包括結(jié)束,因此在圖6-35中會(huì)包含下標(biāo)為0、1、2、3的4個(gè)值。

(2)集合

Redis的集合與Python的集合一樣,沒有順序,值不重復(fù)。往集合中添加數(shù)據(jù),使用的關(guān)鍵字為“sadd”。這里的“s”對(duì)應(yīng)的是英文單詞“set”(集合)。使用格式為:

sadd key value1 value2 value3

安裝Redis-py

pip install redis

MongoDB的優(yōu)化建議

少讀少寫少更新

  • 建議把要插入到MongoDB中的數(shù)據(jù)先統(tǒng)一放到一個(gè)列表中,等積累到一定量再一次性插入
  • 對(duì)于讀數(shù)據(jù),在內(nèi)存允許的情況下,應(yīng)該一次性把數(shù)據(jù)讀入內(nèi)存,盡量減少對(duì)MongoDB的讀取操作。
  • 在某些情況下,更新操作不得不逐條進(jìn)行。建議,把更新這個(gè)動(dòng)作改為插入。這樣就可以實(shí)現(xiàn)批量更新的效果了。具體來說,就是把數(shù)據(jù)批量插入到一個(gè)新的MongoDB集合中,再把原來的集合刪除,最后將新的集合改為原來集合的名字。

能用Redis就不用MongoDB

為了提高效率,就需要引入Redis。由于Redis是基于內(nèi)存的數(shù)據(jù)庫,因此即使頻繁對(duì)其讀/寫,對(duì)性能的影響也遠(yuǎn)遠(yuǎn)小于頻繁讀/寫MongoDB。在Redis中創(chuàng)建一個(gè)集合“crawled_url”,爬蟲在爬一個(gè)網(wǎng)址之前,先把這個(gè)網(wǎng)址sadd到這個(gè)集合中。如果返回為1,那么表示這個(gè)網(wǎng)址之前沒有爬過,爬蟲需要去爬取詳情頁。如果返回0,表示這個(gè)網(wǎng)址之前已經(jīng)爬過了,就不需要再爬了。示例代碼片段如下:

for url in url_list: #url_list為在貼吧列表頁得到的每一個(gè)帖子的詳情頁網(wǎng)址列表if client.sadd('crawled_url', url) == 1:crawl(url)

練習(xí)

目標(biāo)網(wǎng)站:http://dongyeguiwu.zuopinj.com/5525/。

目標(biāo)內(nèi)容:小說《白夜行》第一章到第十三章的正文內(nèi)容。

任務(wù)要求:編寫兩個(gè)爬蟲,爬蟲1從http://dongyeguiwu.zuopinj.com/ 5525/獲取小說《白夜行》第一章到第十三章的網(wǎng)址,并將網(wǎng)址添加到Redis里名為url_queue的列表中。爬蟲2從Redis里名為url_queue的列表中讀出網(wǎng)址,進(jìn)入網(wǎng)址爬取每一章的具體內(nèi)容,再將內(nèi)容保存到MongoDB中。

# 1 使用XPath獲取每一章的網(wǎng)址,再將它們添加到Redis中。其核心代碼如下: url_list = selector.xpath('//div[@class="book_list"]/ul/li/a/@href') for url in url_list:client.lpush('url_queue', url)# 2 對(duì)于爬取正文的爬蟲,只要發(fā)現(xiàn)Redis里的url_queue這個(gè)列表不為空,就要從里面讀出網(wǎng)址,并爬取數(shù)據(jù)。因此,其代碼如下: content_list = [] while client.llen('url_queue') > 0:url = client.lpop('url_queue').decode()source = requests.get(url).contentselector = html.fromstring(source) chapter_name = selector.xpath('//div[@class="h1title"]/h1/text()')[0] content = selector.xpath('//div[@id="htmlContent"]/p/text()') content_list.append({'title': chapter_name, 'content': '\n'.join(content)}) handler.insert(content_list)

調(diào)試與運(yùn)行

爬蟲1運(yùn)行結(jié)束以后,Redis中應(yīng)該會(huì)出現(xiàn)一個(gè)名為url_queue的列表,執(zhí)行以下代碼:

llen url_queue

爬蟲2運(yùn)行結(jié)束以后,Redis中的url_queue會(huì)消失,同時(shí)MongoDB中會(huì)保存小說每一章的內(nèi)容。

小結(jié)

本章主要講解了MongoDB與Redis的使用。其中,MongoDB主要用來存放爬蟲爬到的各種需要持久化保存的數(shù)據(jù),而Redis則用來存放各種中間數(shù)據(jù)

通過減少頻繁讀/寫MongoDB,并使用Redis來彌補(bǔ)MongoDB的一些不足,可以顯著提高爬蟲的運(yùn)行效率。

動(dòng)手實(shí)踐

如果爬蟲1把10000個(gè)網(wǎng)址添加到url_queue中,爬蟲2同時(shí)運(yùn)行在3臺(tái)計(jì)算機(jī)上,請(qǐng)觀察能實(shí)現(xiàn)什么效果。


第7章 異步加載與請(qǐng)求頭

知識(shí)點(diǎn)

  • 抓取異步加載的數(shù)據(jù)。
  • 偽造HTTP請(qǐng)求頭。
  • 模擬瀏覽器獲取網(wǎng)站數(shù)據(jù)。

AJAX版登錄頁面的爬取

通過POST提交請(qǐng)求解決了AJAX版登錄頁面的爬取

小結(jié)

本章主要介紹了使用爬蟲獲取異步加載網(wǎng)頁的各種方法。對(duì)于普通的異步加載,可以使用requests直接發(fā)送AJAX請(qǐng)求來獲取被加載的內(nèi)容。

發(fā)送的請(qǐng)求中可能包含一些特殊的值,這些值來自網(wǎng)頁源代碼或者另一個(gè)AJAX請(qǐng)求。

在發(fā)送請(qǐng)求時(shí)需要注意,應(yīng)保持requests提交的請(qǐng)求頭與瀏覽器的請(qǐng)求頭一致,這樣才能更好地騙過網(wǎng)站服務(wù)器達(dá)到獲取數(shù)據(jù)的目的。

對(duì)于比較復(fù)雜的異步加載,現(xiàn)階段可以先使用Selenium和ChromeDriver來直接加載網(wǎng)頁,然后就能從被加載的網(wǎng)頁中直接獲取到需要的內(nèi)容。


第8章 模擬登錄與驗(yàn)證碼

知識(shí)點(diǎn)

  • 使用Selenium操作瀏覽器實(shí)現(xiàn)自動(dòng)登錄網(wǎng)站。
  • 使用Cookies登錄網(wǎng)站。
  • 模擬表單登錄網(wǎng)站。
  • 爬蟲識(shí)別簡(jiǎn)單的驗(yàn)證碼。

模擬登錄有多種實(shí)現(xiàn)方法

  • 使用Selenium操作瀏覽器登錄
  • 使用Cookies登錄雖然簡(jiǎn)單粗暴
  • 使用模擬提交表單登錄雖然較為麻煩,但可以實(shí)現(xiàn)自動(dòng)化

使用Cookies登錄

Cookie是用戶使用瀏覽器訪問網(wǎng)站的時(shí)候網(wǎng)站存放在瀏覽器中的一小段數(shù)據(jù)。Cookie的復(fù)數(shù)形式Cookies用來表示各種各樣的Cookie。它們有些用來記錄用戶的狀態(tài)信息;有些用來記錄用戶的操作行為;還有一些,具有現(xiàn)代網(wǎng)絡(luò)最重要的功能:記錄授權(quán)信息——用戶是否登錄以及用戶登錄哪個(gè)賬號(hào)。

為了不讓用戶每次訪問網(wǎng)站都進(jìn)行登錄操作,瀏覽器會(huì)在用戶第一次登錄成功以后放一段加密的信息在Cookies中。下次用戶訪問,網(wǎng)站先檢查Cookies有沒有這個(gè)加密信息,如果有并且合法,那么就跳過登錄操作,直接進(jìn)入登錄后的頁面。

使用Cookie來登錄網(wǎng)頁,不僅可以繞過登錄步驟,還可以繞過網(wǎng)站的驗(yàn)證碼。

使用了requests的Session模塊。

所謂Session,是指一段會(huì)話。網(wǎng)站會(huì)把每一個(gè)會(huì)話的ID(Session ID)保存在瀏覽器的Cookies中用來標(biāo)識(shí)用戶的身份。requests的Session模塊可以自動(dòng)保存網(wǎng)站返回的一些信息。其實(shí)在前面章節(jié)中使用的requests.get(),在底層還是會(huì)先創(chuàng)建一個(gè)Session,然后用Session去訪問。

對(duì)于HTTPS的網(wǎng)站,在requests發(fā)送請(qǐng)求的時(shí)候需要帶上verify=False這個(gè)參數(shù),否則爬蟲會(huì)報(bào)錯(cuò)。

帶上這個(gè)參數(shù)以后,爬蟲依然會(huì)報(bào)一個(gè)警告,這是因?yàn)闆]有HTTPS的證書。

對(duì)于HTTPS的網(wǎng)站,在requests發(fā)送請(qǐng)求的時(shí)候需要帶上verify=False這個(gè)參數(shù),否則爬蟲會(huì)報(bào)錯(cuò)。

模擬表單登錄

  • 通過POST提交請(qǐng)求解決了AJAX版登錄頁面的爬取。
  • 但是在現(xiàn)實(shí)中,有更多的網(wǎng)站是使用表單提交的方式來進(jìn)行登錄的。

使用requests的Session模塊來模擬這個(gè)登錄

驗(yàn)證碼 - 肉眼打碼

1.借助瀏覽器

在模擬登錄中講到過Cookies,通過Cookies能實(shí)現(xiàn)繞過登錄,從而直接訪問需要登錄的網(wǎng)站。因此,對(duì)于需要輸入驗(yàn)證碼才能進(jìn)行登錄的網(wǎng)站,可以手動(dòng)在瀏覽器登錄網(wǎng)站,并通過Chrome獲取Cookies,然后使用Cookies來訪問網(wǎng)站。這樣就可以實(shí)現(xiàn)人工輸入一次驗(yàn)證碼,然后很長(zhǎng)時(shí)間不再登錄。

2.不借助瀏覽器

對(duì)于僅僅需要識(shí)別圖片的驗(yàn)證碼,可以使用這種方式——先把驗(yàn)證碼下載到本地,然后肉眼去識(shí)別并手動(dòng)輸入給爬蟲。

驗(yàn)證碼 - 自動(dòng)打碼

1.Python圖像識(shí)別

Python的強(qiáng)大,在于它有非常多的第三方庫。 對(duì)于驗(yàn)證碼識(shí)別,Python也有現(xiàn)成的庫來使用。開源的OCR庫pytesseract配合圖像識(shí)別引擎tesseract,可以用來將圖片中的文字轉(zhuǎn)換為文本。這種方式在爬蟲中的應(yīng)用并不多見。因?yàn)楝F(xiàn)在大部分的驗(yàn)證碼都加上了干擾的紋理,已經(jīng)很少能用單機(jī)版的圖片識(shí)別方式來識(shí)別了。所以如果使用這種方式,只有兩種情況:網(wǎng)站的驗(yàn)證碼極其簡(jiǎn)單工整,使用大量的驗(yàn)證碼來訓(xùn)練tesseract。

(1)安裝tesseract

brew install tesseract

(2)安裝Python庫

要使用tesseract來進(jìn)行圖像識(shí)別,需要安裝兩個(gè)第三方庫:

pip install Pillowpip install pytesseract# 其中,Pillow是Python中專門用來處理圖像的第三方庫,pytesseract是專門用來操作tesseract的第三方庫。

(3)tesseract的使用

① 導(dǎo)入pytesseract和Pillow。

② 打開圖片。

③ 識(shí)別。

import pytesseract from PIL import Image image = Image.open('驗(yàn)證碼.png') code = pytesseract.image_to_string(image) print(code)

2.打碼網(wǎng)站

(1)打碼網(wǎng)站介紹

在線驗(yàn)證碼識(shí)別的網(wǎng)站,簡(jiǎn)稱打碼網(wǎng)站。這些網(wǎng)站有一些是使用深度學(xué)習(xí)技術(shù)識(shí)別驗(yàn)證碼,有一些是雇傭了很多人來人肉識(shí)別驗(yàn)證碼

網(wǎng)站提供了接口來實(shí)現(xiàn)驗(yàn)證碼識(shí)別服務(wù)。使用打碼網(wǎng)站理論上可以識(shí)別任何使用輸入方式來驗(yàn)證的驗(yàn)證碼。

(2)使用在線打碼

在百度或者谷歌上面搜索“驗(yàn)證碼在線識(shí)別”,就可以找到很多提供在線打碼的網(wǎng)站。但是由于一般這種打碼網(wǎng)站是需要交費(fèi)才能使用的,所以要注意財(cái)產(chǎn)安全。

云打碼

練習(xí):自動(dòng)登錄果殼網(wǎng)

目標(biāo)網(wǎng)站:https://www.guokr.com。

目標(biāo)內(nèi)容:個(gè)人資料設(shè)置界面源代碼。

使用模擬登錄與驗(yàn)證碼識(shí)別的技術(shù)實(shí)現(xiàn)自動(dòng)登錄果殼網(wǎng)。 果殼網(wǎng)的登錄界面有驗(yàn)證碼,請(qǐng)使用人工或者在線打碼的方式識(shí)別驗(yàn)證碼,并讓爬蟲登錄。登錄以后可以正確顯示“個(gè)人資料設(shè)置”界面的源代碼。

涉及的知識(shí)點(diǎn):

  • 爬蟲識(shí)別驗(yàn)證碼。
  • 爬蟲模擬登錄。

小結(jié)

本章主要講授了模擬登錄與驗(yàn)證碼識(shí)別。使用Selenium實(shí)現(xiàn)模擬登錄最為簡(jiǎn)單。但是這種方式的弊端是運(yùn)行速度慢。

使用Cookies登錄可以實(shí)現(xiàn)一次手動(dòng)、長(zhǎng)期自動(dòng)的目的。

而模擬表單登錄本質(zhì)就是發(fā)起POST請(qǐng)求來進(jìn)行登錄,需要使用Session模塊來保存登錄信息。

驗(yàn)證碼識(shí)別主要是使需輸入的驗(yàn)證碼實(shí)現(xiàn)自動(dòng)化。包括手動(dòng)輸入與在線打碼。對(duì)于單擊、拖動(dòng)的驗(yàn)證碼,建議使用Cookies來進(jìn)行登錄。


第9章 抓包與中間人爬蟲

知識(shí)點(diǎn)

  • 使用Charles抓取App和微信小程序的數(shù)據(jù)包。
  • 使用mitmproxy開發(fā)中間人爬蟲。

數(shù)據(jù)抓包

所謂抓包(Package Capture),簡(jiǎn)單來說,就是在網(wǎng)絡(luò)數(shù)據(jù)傳輸?shù)倪^程中對(duì)數(shù)據(jù)包進(jìn)行截獲、查看、修改或轉(zhuǎn)發(fā)的過程。

如果把網(wǎng)絡(luò)上發(fā)送與接收的數(shù)據(jù)包理解為快遞包裹,那么在快遞運(yùn)輸?shù)倪^程中查看里面的內(nèi)容,這就是抓包。

Charles

要簡(jiǎn)化尋找數(shù)據(jù)的過程,就需要設(shè)法直接全局搜索網(wǎng)頁的所有請(qǐng)求的返回?cái)?shù)據(jù)。

為了實(shí)現(xiàn)這個(gè)目的,就需要使用Charles。Charles是一個(gè)跨平臺(tái)的HTTP抓包工具。使用它可以像Chrome一樣截取HTTP或者HTTPS請(qǐng)求的數(shù)據(jù)包。

抓取HTTPS數(shù)據(jù)包

用Charles抓取HTTPS數(shù)據(jù)包時(shí)的請(qǐng)求會(huì)大量失敗。出現(xiàn)這種情況,是因?yàn)闆]有安裝SSL證書導(dǎo)致的。

第一步,安裝好證書:要安裝SSL證書,可選擇菜單欄的“Help”- “SSL Proxying”-“Install Charles Root Certificate”命令。

第二步,設(shè)置SSL代理:安裝好證書以后,選擇菜單欄中的“Proxy”-“SSL Proxying Settings”命令打開SSL代理設(shè)置對(duì)話框。

iOS系統(tǒng)的配置和使用

對(duì)于蘋果設(shè)備,首先要保證計(jì)算機(jī)和蘋果設(shè)備聯(lián)在同一個(gè)Wi-Fi上。選擇Charles菜單欄中的“Help”-“Local IP Address”命令,此時(shí)彈出一個(gè)對(duì)話框,顯示當(dāng)前計(jì)算機(jī)的內(nèi)網(wǎng)IP地址。

接下來設(shè)置手機(jī)。進(jìn)入系統(tǒng)設(shè)置,選擇“無線局域網(wǎng)”,然后單擊已經(jīng)連接的這個(gè)Wi-Fi熱點(diǎn)右側(cè)的圓圈包圍的字母i的圖標(biāo)。

第一步,在手機(jī)上設(shè)置HTTP代理。

第二步,使用iOS系統(tǒng)自帶的Safari瀏覽器訪問https://chls.pro/ssl。安裝證書。

第三步,證書信任設(shè)置

Android的配置和使用

將Charles的證書保存到計(jì)算機(jī)桌面

微信小程序爬蟲

小程序的請(qǐng)求極其簡(jiǎn)單,基本上沒有驗(yàn)證信息,即便有驗(yàn)證信息也非常脆弱。

用Python來請(qǐng)求小程序的后臺(tái)接口從而獲取數(shù)據(jù),比請(qǐng)求異步加載網(wǎng)頁的后臺(tái)接口要容易很多。

在爬蟲開發(fā)過程中,如果目標(biāo)網(wǎng)站有微信小程序,那么一定要優(yōu)先調(diào)查能否通過小程序的接口來抓取數(shù)據(jù)。

小程序的反爬蟲能力比網(wǎng)頁版的低很多。使用小程序的接口來爬數(shù)據(jù),能極大提高爬蟲的開發(fā)效率。

Charles的局限

  • Charles只能截獲HTTP和HTTPS的數(shù)據(jù)包,如果網(wǎng)站使用的是websocket或者是flashsocket,那么Charles就無能為力。
  • 有一些App會(huì)自帶證書,使用其他證書都無法正常訪問后臺(tái)接口。在這種情況下,Charles自帶的證書就不能正常使用,也就沒有辦法抓取這種App的數(shù)據(jù)。
  • 有一些App的數(shù)據(jù)經(jīng)過加密,App接收到數(shù)據(jù)以后在其內(nèi)部進(jìn)行解密。
  • 對(duì)于這種情況,Charles只能抓取到經(jīng)過加密的數(shù)據(jù)。如果無法知道數(shù)據(jù)的具體加密方法,就沒有辦法解讀Charles抓取到的數(shù)據(jù)。

中間人爬蟲

中間人(Man-in-the-Middle,MITM)攻擊是指攻擊者與通信的兩端分別創(chuàng)建獨(dú)立的聯(lián)系,并交換其所收到的數(shù)據(jù),使通信的兩端認(rèn)為其正在通過一個(gè)私密的連接與對(duì)方直接對(duì)話,但事實(shí)上整個(gè)會(huì)話都被攻擊者完全控制。

在中間人攻擊中,攻擊者可以攔截通信雙方的通話,并插入新的內(nèi)容或者修改原有內(nèi)容。

例如:上課傳紙條

中間人爬蟲就是利用了中間人攻擊的原理來實(shí)現(xiàn)數(shù)據(jù)抓取的一種爬蟲技術(shù)。

數(shù)據(jù)抓包就是中間人爬蟲的一個(gè)簡(jiǎn)單應(yīng)用。所以使用Charles也是一種中間人攻擊。

mitmproxy的介紹和安裝

要安裝mitmproxy,首先需要保證系統(tǒng)的Python為Python 3.5或者更高版本

brew install mitmproxy

mitmproxy使用

  • 運(yùn)行mitmproxy會(huì)彈出對(duì)話框詢問
mitmproxy
  • mitmproxy的端口為8080端口,在瀏覽器或者在手機(jī)上設(shè)置代理,代理IP為計(jì)算機(jī)IP,端口為8080端口。
  • 設(shè)置好代理以后,在手機(jī)上打開一個(gè)App或者打開一個(gè)網(wǎng)頁,可以看到mitmproxy上面有數(shù)據(jù)滾動(dòng)。
  • 此時(shí)只能訪問HTTP網(wǎng)站,要訪問HTTPS網(wǎng)站,還需要安裝mitmproxy的證書。在手機(jī)設(shè)置了mitmproxy的代理以后,通過手機(jī)瀏覽器訪問http://mitm.it/這個(gè)網(wǎng)址。

使用Python定制mitmproxy

mitmproxy的強(qiáng)大之處在于它還自帶一個(gè)mitmdump命令。這個(gè)命令可以用來運(yùn)行符合一定規(guī)則的Python腳本,并在Python腳本里面直接操作HTTP和HTTPS的請(qǐng)求,以及返回的數(shù)據(jù)包。

為了自動(dòng)化地監(jiān)控網(wǎng)站或者手機(jī)發(fā)出的請(qǐng)求頭部信息和Body信息,并接收網(wǎng)站返回的頭部信息和Body信息,就需要掌握如何在Python腳本中獲得請(qǐng)求和返回的數(shù)據(jù)包。

mitmdump的使用場(chǎng)景

  • 網(wǎng)站返回的Headers中經(jīng)常有Cookies。
  • mitmdump的腳本使用print()函數(shù)把Cookies打印出來,然后通過管道傳遞給另一個(gè)普通的正常的Python腳本。
  • 在另一個(gè)腳本里面,得到管道傳遞進(jìn)來的Cookies,再把它放進(jìn)Redis里面。

需求分析

目標(biāo)App:Keep。

目標(biāo)內(nèi)容:Keep是當(dāng)下熱門的健身App,本次案例的目的是要使用抓包的方式爬取Keep的熱門動(dòng)態(tài)。

涉及的知識(shí)點(diǎn):

  • 使用Charles或者mitmproxy抓包。
  • 開發(fā)App爬蟲。

小結(jié)

  • 抓包是爬蟲開發(fā)過程中非常有用的一個(gè)技巧。使用Charles,可以把爬蟲的爬取范圍從網(wǎng)頁瞬間擴(kuò)展到手機(jī)App和微信小程序。
  • 由于微信小程序的反爬蟲機(jī)制在大多數(shù)情況下都非常脆弱,所以如果目標(biāo)網(wǎng)站有微信小程序,那么可以大大簡(jiǎn)化爬蟲的開發(fā)難度。
  • 當(dāng)然,網(wǎng)站有可能會(huì)對(duì)接口的數(shù)據(jù)進(jìn)行加密,App得到密文以后,使用內(nèi)置的算法進(jìn)行解密。對(duì)于這種情況,單純使用抓包就沒有辦法處理了,就需要使用下一章所要講到的技術(shù)來解決。
  • 使用mitmproxy可以實(shí)現(xiàn)爬蟲的全自動(dòng)化操作。
  • 對(duì)于擁有復(fù)雜參數(shù)的網(wǎng)站,使用這種先抓包再提交的方式可以在一定程度上繞過網(wǎng)站的反爬蟲機(jī)制,從而實(shí)現(xiàn)數(shù)據(jù)抓取。

第10章 Android原生App爬蟲

知識(shí)點(diǎn)

那么有沒有什么辦法可以做到幾乎毫無痕跡地爬取數(shù)據(jù)呢?答案是有。當(dāng)然可能有讀者會(huì)認(rèn)為可以使用Selenium + ChromeDriver。這種方式只能操作網(wǎng)頁。本章將要介紹針對(duì)Android原生App的爬蟲。

  • Android測(cè)試環(huán)境的搭建。
  • 使用Python操作Android手機(jī)。
  • 使用Python操作Android手機(jī)實(shí)現(xiàn)爬蟲。

實(shí)現(xiàn)原理

目前,Android App主要有兩種實(shí)現(xiàn)形式。第一種是Android原生App。這種App的全部或者大部分內(nèi)容使用Android提供的各個(gè)接口來開發(fā),例如Android版的微信就是一個(gè)Android原生的App。第二種是基于網(wǎng)頁的App。這種App本質(zhì)上就是一個(gè)瀏覽器,里面的所有內(nèi)容實(shí)際上都是網(wǎng)頁。例如,12306的App就是這樣一種基于網(wǎng)頁的App。

Android原生App爬蟲(以下簡(jiǎn)稱App爬蟲)可以直接讀取Android原生App上面的文本信息。

UI Automator Viewer

設(shè)置好環(huán)境變量以后,在終端窗口輸入“uiautomatorviewer”并按Enter鍵,如果彈出UI Automator Viewer窗口,表明環(huán)境設(shè)置成功。

Android手機(jī)連接到計(jì)算機(jī)上,保持手機(jī)屏幕為亮起狀態(tài),單擊UI Automator Viewer左上角文件夾右側(cè)的手機(jī)圖標(biāo),如果能夠看到手機(jī)屏幕出現(xiàn)在窗口中,則表示一切順利,環(huán)境搭建成功完成。如果在這個(gè)過程中手機(jī)彈出了任何警告窗口,都選擇“運(yùn)行”或者“確定”。

使用Python操縱手機(jī)

pip install uiautomator

有一點(diǎn)需要特別說明,UI Automator Viewer與Python uiautomator不能同時(shí)使用。

與Selenium一樣,要操作手機(jī)上面的元素,首先要找到被操作的東西。以打開微信為例,首先翻到有微信的那一頁

from uiautomator import Device device = Device() device(text='微信').click()

如果計(jì)算機(jī)上面只連接了一臺(tái)Android手機(jī),那么初始化設(shè)備連接只需要使用device = Device()即可。那么如果計(jì)算機(jī)上連接了很多臺(tái)手機(jī),該怎么辦呢?此時(shí)就需要指定手機(jī)的串號(hào)。要查看手機(jī)串號(hào),需要在終端輸入以下命令:

adb devices -l

從輸出的內(nèi)容可以看到手機(jī)的串號(hào)

選擇器

如何知道有哪些選擇器可供使用呢?請(qǐng)執(zhí)行以下代碼:

from uiautomator import Device device = Device() print(device.dump())

此時(shí)終端會(huì)以XML輸出當(dāng)前手機(jī)屏幕顯示的窗口布局信息。

這里的XML就相當(dāng)于網(wǎng)頁中的HTML,用來描述窗口上面各個(gè)部分的布局信息。

XML的格式與HTML非常像,格式為:<標(biāo)簽 屬性1=“屬性值1” 屬性2=“屬性值2”>文本</標(biāo)簽>

操作

  • 獲得屏幕文字;
  • 滾動(dòng)屏幕;
  • 滑動(dòng)屏幕;
  • 點(diǎn)擊屏幕;
  • 輸入文字;
  • 判斷元素是否存在;
  • 點(diǎn)亮關(guān)閉屏幕;
  • 操作實(shí)體按鍵;
  • watcher。

多設(shè)備應(yīng)用(群控)

使用uiautomator來做爬蟲開發(fā),最主要的瓶頸在于速度。因?yàn)槠聊簧系脑丶虞d是需要時(shí)間的,這個(gè)時(shí)間受到手機(jī)性能和網(wǎng)速的多重限制。因此比較好的辦法是使用多臺(tái)Android手機(jī)實(shí)現(xiàn)分布式抓取。使用USBHub擴(kuò)展計(jì)算機(jī)的USB口以后,一臺(tái)計(jì)算機(jī)控制30臺(tái)Android手機(jī)是完全沒有問題的。只要能實(shí)現(xiàn)良好的調(diào)度和任務(wù)派分邏輯,就可以大大提高數(shù)據(jù)的抓取效率。

App爬蟲系統(tǒng)架構(gòu)的形式

練習(xí):BOSS直聘爬蟲

任務(wù)目標(biāo):BOSS直聘App。
BOSS直聘是一個(gè)招聘App,在上面可以看到很多的工作。 App職位列表如圖10-44所示。
使用uiautomator開發(fā)一個(gè)爬蟲,從手機(jī)上爬取每一個(gè)職位的名稱、薪資、招聘公司、公司地址、工作經(jīng)驗(yàn)要求和學(xué)歷。

小結(jié)

  • 本章主要講解了如何通過Python操作手機(jī)來獲取Android原生App中的文字內(nèi)容。Python使用uiautomator這個(gè)第三方庫來操作Android手機(jī)的UiAutomator,從而實(shí)現(xiàn)模擬人們對(duì)手機(jī)屏幕的任何操作行為,并直接讀取屏幕上的文字。
  • 使用uiautomator來開發(fā)爬蟲,要打通流程非常簡(jiǎn)單。但是需要特別注意處理各種異常的情況。同時(shí),由于手機(jī)速度的問題,應(yīng)該使用多臺(tái)手機(jī)構(gòu)成一個(gè)集群來提高抓取的速率。
  • 最后,如果使用手機(jī)集群來進(jìn)行數(shù)據(jù)抓取,并且需要抓取的App數(shù)據(jù)來自網(wǎng)絡(luò),那么需要考慮無線路由器的負(fù)荷。當(dāng)同時(shí)連接無線路由器的設(shè)備超過一定數(shù)量時(shí),有可能導(dǎo)致部分甚至所有設(shè)備都無法上網(wǎng)。這就需要使用工業(yè)級(jí)路由器來緩解。
  • 無線信號(hào)相互干擾也是一個(gè)比較麻煩的問題。使用5G信道能緩解,但一般便宜的Android手機(jī)不支持5G的Wi-Fi信道,此時(shí)能做的就是把手機(jī)盡量分開,不要放在一起。使用電磁屏蔽網(wǎng),將每10個(gè)手機(jī)和一個(gè)無線路由器為一組包裹起來,也能起到一定的阻隔Wi-Fi信號(hào)的作用。

練習(xí)

使用Android手機(jī)來爬取一個(gè)原生App的數(shù)據(jù)。


第11章 Scrapy

知識(shí)點(diǎn)

  • 在Windows、Mac OS和Linux下搭建Scrapy環(huán)境。
  • 使用Scrapy獲取網(wǎng)絡(luò)源代碼。
  • 在Scrapy中通過XPath解析數(shù)據(jù)。
  • 在Scrapy中使用MongoDB。
  • 在Scrapy中使用Redis。

在Mac OS下安裝Scrapy

pip install scrapy

創(chuàng)建項(xiàng)目

$ scrapy startproject offcn # offcn 是項(xiàng)目名$ cd offcn $ scrapy genspider jobbank zw.offcn.com # jobbank 是爬蟲名 # zw.offcn.com 是爬取的網(wǎng)址# 運(yùn)行 $ scrapy crawl jobbank

那么如何使用PyCharm來運(yùn)行或者調(diào)試Scrapy的爬蟲呢?

為了實(shí)現(xiàn)這個(gè)目的,需要?jiǎng)?chuàng)建另外一個(gè)Python文件。文件名可以取任意合法的文件名。這里以“main.py”為例。

main.py文件內(nèi)容如下:

from scrapy import cmdline cmdline.execute("scrapy crawl jobbank".split())

Scrapy的工程結(jié)構(gòu)

  • spiders文件夾:存放爬蟲文件的文件夾。
  • items.py:定義需要抓取的數(shù)據(jù)。
  • pipelines.py:負(fù)責(zé)數(shù)據(jù)抓取以后的處理工作。
  • settings.py:爬蟲的各種配置信息。

但是為什么還有items.py和pipelines.py這兩個(gè)文件呢?這是由于Scrapy的理念是將數(shù)據(jù)爬取和數(shù)據(jù)處理分開。

items.py文件用于定義需要爬取哪些內(nèi)容。

pipelines.py文件用于對(duì)數(shù)據(jù)做初步的處理,包括但不限于初步清洗數(shù)據(jù)、存儲(chǔ)數(shù)據(jù)等。在pipelines中可以將數(shù)據(jù)保存到MongoDB。

Scrapy與MongoDB

一個(gè)Scrapy工程可以有多個(gè)爬蟲;再看items.py文件,可以發(fā)現(xiàn),在一個(gè)items.py里面可以對(duì)不同的爬蟲定義不同的抓取內(nèi)容Item。

接下來設(shè)置pipelines.py。在這個(gè)文件中,需要寫出將數(shù)據(jù)保存到MongoDB的代碼。而這里的代碼,就是最簡(jiǎn)單的初始化MongoDB的連接,保存數(shù)據(jù)。

Scrapy與Redis

Scrapy是一個(gè)分布式爬蟲的框架,如果把它像普通的爬蟲一樣單機(jī)運(yùn)行,它的優(yōu)勢(shì)將不會(huì)被體現(xiàn)出來。

因此,要讓Scrapy往分布式爬蟲方向發(fā)展,就需要學(xué)習(xí)Scrapy與Redis的結(jié)合使用。Redis在Scrapy的爬蟲中作為一個(gè)隊(duì)列存在。

使用Redis緩存網(wǎng)頁并自動(dòng)去重

pip install scrapy_redis

小結(jié)

本章主要講了Python分布式爬蟲框架Scrapy的安裝和使用。

Scrapy在Windows中的安裝最為煩瑣,在Mac OS中的安裝最為簡(jiǎn)單。

由于Scrapy需要依賴非常多的第三方庫文件,因此建議無論使用哪個(gè)系統(tǒng)安裝,都要將Scrapy安裝到Virtualenv創(chuàng)建的虛擬Python環(huán)境中,從而避免影響系統(tǒng)的Python環(huán)境。

使用Scrapy爬取網(wǎng)頁,最核心的部分是構(gòu)建XPath。而其他的各種配置都是一次配好、終生使用的。由于Scrapy的理念是將數(shù)據(jù)抓取的動(dòng)作和數(shù)據(jù)處理的動(dòng)作分開,因此對(duì)于數(shù)據(jù)處理的各種邏輯應(yīng)該讓pipeline來處理。數(shù)據(jù)抓取的部分只需要關(guān)注如何使用XPath提取數(shù)據(jù)。數(shù)據(jù)提取完成以后,提交給pipeline處理即可。

由于Scrapy爬蟲爬取數(shù)據(jù)是異步操作,所以從一個(gè)頁面跳到另一個(gè)頁面是異步的過程,需要使用回調(diào)函數(shù)。

Scrapy爬取到的數(shù)據(jù)量非常大,所以應(yīng)該使用數(shù)據(jù)庫來保存。使用MongoDB會(huì)讓數(shù)據(jù)保存工作變得非常簡(jiǎn)單。

要讓Scrapy使用MongoDB,只需要在pipeline中配置好數(shù)據(jù)保存的流程,再在settings.py中配置好ITEM_PIPELINES和MongoDB的信息即可。

使用Redis做緩存是從爬蟲邁向分布式爬蟲的一個(gè)起點(diǎn)。

Scrapy安裝scrapy_redis組件以后,就可以具備使用Redis的能力。

在Scrapy中使用Redis需要修改爬蟲的父類,需要在settings.py中設(shè)置好爬蟲的調(diào)度和去重。

同時(shí)對(duì)于Python 3,需要修改scrapy_redis的一行代碼,才能讓爬蟲正常運(yùn)行。

練習(xí)

請(qǐng)完成網(wǎng)站爬蟲開發(fā),并實(shí)現(xiàn)爬蟲的翻頁功能,從而可以爬到1~5頁所有的文章。下一頁的URL請(qǐng)使用爬蟲從當(dāng)前頁面獲取,切勿根據(jù)URL的規(guī)律手動(dòng)構(gòu)造。

提示,對(duì)于翻頁功能,實(shí)際上相當(dāng)于將回調(diào)函數(shù)的函數(shù)名寫成它自己的: callback=self.parse。parse方法可自己調(diào)用自己,不過傳入的URL是下一頁的URL。這有點(diǎn)像遞歸,不過遞歸用的是return,而這里用的是yield。

請(qǐng)思考一個(gè)問題,在請(qǐng)求文章詳情頁的時(shí)候,設(shè)置了請(qǐng)求頭,但是Scrapy請(qǐng)求文章列表頁的時(shí)候,在哪里設(shè)置請(qǐng)求頭?請(qǐng)求列表頁的時(shí)候,爬蟲直接從Redis得到網(wǎng)址,自動(dòng)發(fā)起了請(qǐng)求,完全沒讓開發(fā)者自己設(shè)置請(qǐng)求頭。這其實(shí)是一個(gè)非常大的隱患,因?yàn)椴辉O(shè)置請(qǐng)求頭,網(wǎng)站立刻就能知道這個(gè)請(qǐng)求來自Scrapy,這是非常危險(xiǎn)的。

請(qǐng)讀者查詢scrapy_redis的文檔,查看如何使用make_requests_ from_url(self, url)這個(gè)方法。


第12章 Scrapy高級(jí)應(yīng)用

知識(shí)點(diǎn)

  • 開發(fā)Scrapy中間件。
  • 使用Scrapyd部署爬蟲。
  • Nginx的安裝和反向代理。
  • 了解爬蟲的分布式框架。

Middleware

中間件是Scrapy里面的一個(gè)核心概念。使用中間件可以在爬蟲的請(qǐng)求發(fā)起之前或者請(qǐng)求返回之后對(duì)數(shù)據(jù)進(jìn)行定制化修改,從而開發(fā)出適應(yīng)不同情況的爬蟲。

“中間件”這個(gè)中文名字和前面章節(jié)講到的“中間人”只有一字之差。它們做的事情確實(shí)也非常相似。中間件和中間人都能在中途劫持?jǐn)?shù)據(jù),做一些修改再把數(shù)據(jù)傳遞出去。不同點(diǎn)在于,中間件是開發(fā)者主動(dòng)加進(jìn)去的組件,而中間人是被動(dòng)的,一般是惡意地加進(jìn)去的環(huán)節(jié)。

中間件主要用來輔助開發(fā),而中間人卻多被用來進(jìn)行數(shù)據(jù)的竊取、偽造甚至攻擊。

在Scrapy中有兩種中間件:下載器中間件(Downloader Middleware)和爬蟲中間件(Spider Middleware)。

Downloader Middleware

更換代理IP,更換Cookies,更換User-Agent,自動(dòng)重試。

加入中間件以后的爬蟲流程

開發(fā)代理中間件

代理中間件的可用代理列表不一定非要寫在settings.py里面,也可以將它們寫到數(shù)據(jù)庫或者Redis中。一個(gè)可行的自動(dòng)更換代理的爬蟲系統(tǒng),應(yīng)該有如下的3個(gè)功能。

  • 有一個(gè)小爬蟲ProxySpider去各大代理網(wǎng)站爬取免費(fèi)代理并驗(yàn)證,將可以使用的代理IP保存到數(shù)據(jù)庫中。
  • 在ProxyMiddlerware的process_request中,每次從數(shù)據(jù)庫里面隨機(jī)選擇一條代理IP地址使用。
  • 周期性驗(yàn)證數(shù)據(jù)庫中的無效代理,及時(shí)將其刪除。

激活中間件

中間件寫好以后,需要去settings.py中啟動(dòng)。

Scrapy自帶中間件及其順序編號(hào)

開發(fā)UA中間件

從settings.py配置好的UA列表中隨機(jī)選擇一項(xiàng),加入到請(qǐng)求頭中

開發(fā)Cookies中間件

對(duì)于需要登錄的網(wǎng)站,可以使用Cookies來保持登錄狀態(tài)。那么如果單獨(dú)寫一個(gè)小程序,用Selenium持續(xù)不斷地用不同的賬號(hào)登錄網(wǎng)站,就可以得到很多不同的Cookies。由于Cookies本質(zhì)上就是一段文本,所以可以把這段文本放在Redis里面。這樣一來,當(dāng)Scrapy爬蟲請(qǐng)求網(wǎng)頁時(shí),可以從Redis中讀取Cookies并給爬蟲換上。這樣爬蟲就可以一直保持登錄狀態(tài)。

在中間件中集成Selenium

對(duì)于一些很麻煩的異步加載頁面,手動(dòng)尋找它的后臺(tái)API代價(jià)可能太大。這種情況下可以使用Selenium和ChromeDriver或者Selenium和PhantomJS來實(shí)現(xiàn)渲染網(wǎng)頁。

在中間件中集成了Selenium以后,就可以像爬取普通網(wǎng)頁一樣爬取異步加載的頁面

在中間件里重試

在爬蟲的運(yùn)行過程中,可能會(huì)因?yàn)榫W(wǎng)絡(luò)問題或者是網(wǎng)站反爬蟲機(jī)制生效等原因,導(dǎo)致一些請(qǐng)求失敗。在某些情況下,少量的數(shù)據(jù)丟失是無關(guān)緊要的,例如在幾億次請(qǐng)求里面失敗了十幾次,損失微乎其微,沒有必要重試。但還有一些情況,每一條請(qǐng)求都至關(guān)重要,容不得有一次失敗。此時(shí)就需要使用中間件來進(jìn)行重試。

在中間件里處理異常

在默認(rèn)情況下,一次請(qǐng)求失敗了,Scrapy會(huì)立刻原地重試,再失敗再重試,如此3次。如果3次都失敗了,就放棄這個(gè)請(qǐng)求。這種重試邏輯存在一些缺陷。以代理IP為例,代理存在不穩(wěn)定性,特別是免費(fèi)的代理,差不多10個(gè)里面只有3個(gè)能用。而現(xiàn)在市面上有一些收費(fèi)代理IP提供商,購買他們的服務(wù)以后,會(huì)直接提供一個(gè)固定的網(wǎng)址。

把這個(gè)網(wǎng)址設(shè)為Scrapy的代理,就能實(shí)現(xiàn)每分鐘自動(dòng)以不同的IP訪問網(wǎng)站。如果其中一個(gè)IP出現(xiàn)了故障,那么需要等一分鐘以后才會(huì)更換新的IP。在這種場(chǎng)景下,Scrapy自帶的重試邏輯就會(huì)導(dǎo)致3次重試都失敗。

這種場(chǎng)景下,如果能立刻更換代理就立刻更換;如果不能立刻更換代理,比較好的處理方法是延遲重試。而使用Scrapy_redis就能實(shí)現(xiàn)這一點(diǎn)。

爬蟲的請(qǐng)求來自于Redis,請(qǐng)求失敗以后的URL又放回Redis的末尾。

一旦一個(gè)請(qǐng)求原地重試3次還是失敗,那么就把它放到Redis的末尾,這樣Scrapy需要把Redis列表前面的請(qǐng)求都消費(fèi)以后才會(huì)重試之前的失敗請(qǐng)求。這就為更換IP帶來了足夠的時(shí)間。

下載器中間件功能總結(jié)

能在中間件中實(shí)現(xiàn)的功能,都能通過直接把代碼寫到爬蟲中實(shí)現(xiàn)。使用中間件的好處在于,它可以把數(shù)據(jù)爬取和其他操作分開。在爬蟲的代碼里面專心寫數(shù)據(jù)爬取的代碼;在中間件里面專心寫突破反爬蟲、登錄、重試和渲染AJAX等操作。

對(duì)團(tuán)隊(duì)來說,這種寫法能實(shí)現(xiàn)多人同時(shí)開發(fā),提高開發(fā)效率;對(duì)個(gè)人來說,寫爬蟲的時(shí)候不用考慮反爬蟲、登錄、驗(yàn)證碼和異步加載等操作。另外,寫中間件的時(shí)候不用考慮數(shù)據(jù)怎樣提取。一段時(shí)間只做一件事,思路更清晰。

爬蟲中間件

爬蟲中間件的用法與下載器中間件非常相似,只是它們的作用對(duì)象不同。

下載器中間件的作用對(duì)象是請(qǐng)求request和返回response;爬蟲中間鍵的作用對(duì)象是爬蟲,更具體地來說,就是寫在spiders文件夾下面的各個(gè)文件。

Scrapy的數(shù)據(jù)流圖

其中,4、5表示下載器中間件,6、7表示爬蟲中間件。爬蟲中間件會(huì)在以下幾種情況被調(diào)用。

  • 當(dāng)運(yùn)行到y(tǒng)ield scrapy.Request()或者yield item的時(shí)候,爬蟲中間件的process_spider_output()方法被調(diào)用。
  • 當(dāng)爬蟲本身的代碼出現(xiàn)了Exception的時(shí)候,爬蟲中間件的process_spider_exception()方法被調(diào)用。
  • 當(dāng)爬蟲里面的某一個(gè)回調(diào)函數(shù)parse_xxx()被調(diào)用之前,爬蟲中間件的process_spider_input()方法被調(diào)用。
  • 當(dāng)運(yùn)行到start_requests()的時(shí)候,爬蟲中間件的process_start_ requests()方法被調(diào)用。

在中間件處理爬蟲本身的異常

在爬蟲中間件里面可以處理爬蟲本身的異常。

下載器中間件里面的報(bào)錯(cuò)一般是由于外部原因引起的,和代碼層面無關(guān)。而現(xiàn)在的這種報(bào)錯(cuò)是由于代碼本身的問題導(dǎo)致的,是代碼寫得不夠周全引起的。

激活爬蟲中間件

在settings.py中,在下載器中間件配置項(xiàng)的上面就是爬蟲中間件的配置項(xiàng),它默認(rèn)也是被注釋了的,解除注釋,并把自定義的爬蟲中間件添加進(jìn)去即可

幾個(gè)自帶的爬蟲中間件

爬蟲中間件輸入/輸出

在爬蟲中間件里面還有兩個(gè)不太常用的方法,分別為process_ spider_input(response, spider)和process_spider_output(response, result, spider)。其中,process_spider_input(response, spider)在下載器中間件處理完成后,馬上要進(jìn)入某個(gè)回調(diào)函數(shù)parse_xxx()前調(diào)用。

process_spider_output(response, result, output)是在爬蟲運(yùn)行yield item或者yield scrapy.Request()的時(shí)候調(diào)用。

在這個(gè)方法處理完成以后,數(shù)據(jù)如果是item,就會(huì)被交給pipeline;如果是請(qǐng)求,就會(huì)被交給調(diào)度器,然后下載器中間件才會(huì)開始運(yùn)行。

所以在這個(gè)方法里面可以進(jìn)一步對(duì)item或者請(qǐng)求做一些修改。這個(gè)方法的參數(shù)result就是爬蟲爬出來的item或者scrapy.Request()。由于yield得到的是一個(gè)生成器,生成器是可以迭代的,所以result也是可以迭代的,可以使用for循環(huán)來把它展開。

爬蟲的部署

一般情況下,爬蟲會(huì)使用云服務(wù)器來運(yùn)行,這樣可以保證爬蟲24h不間斷運(yùn)行。

FTP:使用FTP來上傳代碼,不僅非常不方便,而且經(jīng)常出現(xiàn)把方向搞反,導(dǎo)致本地最新的代碼被服務(wù)器代碼覆蓋的問題。

Git:好處是可以進(jìn)行版本管理,不會(huì)出現(xiàn)代碼丟失的問題。但操作步驟多,需要先在本地提交,然后登錄服務(wù)器,再從服務(wù)器上面把代碼下載下來。如果有很多服務(wù)器的話,每個(gè)服務(wù)器都登錄并下載一遍代碼是非常浪費(fèi)時(shí)間的事情。

Docker:好處是可以做到所有服務(wù)器都有相同的環(huán)境,部署非常方便。但需要對(duì)Linux有比較深入的了解,對(duì)新人不友好,上手難度比較大。

為了克服上面的種種問題,本書將會(huì)使用Scrapy官方開發(fā)的爬蟲部署、運(yùn)行、管理工具:Scrapyd。

Scrapyd

Scrapyd是Scrapy官方開發(fā)的,用來部署、運(yùn)行和管理Scrapy爬蟲的工具。使用Scrapyd,可以實(shí)現(xiàn)一鍵部署Scrapy爬蟲,訪問一個(gè)網(wǎng)址就啟動(dòng)/停止爬蟲。Scrapyd自帶一個(gè)簡(jiǎn)陋網(wǎng)頁,可以通過瀏覽器看到爬蟲當(dāng)前運(yùn)行狀態(tài)或者查閱爬蟲Log。Scrapyd提供了官方API,從而可以通過二次開發(fā)實(shí)現(xiàn)更多更加復(fù)雜的功能。

Scrapyd可以同時(shí)管理多個(gè)Scrapy工程里面的多個(gè)爬蟲的多個(gè)版本。如果在多個(gè)云服務(wù)器上安裝Scrapyd,可以通過Python寫一個(gè)小程序,來實(shí)現(xiàn)批量部署爬蟲、批量啟動(dòng)爬蟲和批量停止爬蟲。

pip install scrapyd

上傳Scrapy爬蟲的工具

Scrapyd需要安裝到云服務(wù)器上,如果讀者沒有云服務(wù)器,或者想在本地測(cè)試,那么可以在本地也安裝一個(gè)。

接下來需要安裝scrapyd-client,這是用來上傳Scrapy爬蟲的工具,也是Python的一個(gè)第三方庫,使用pip安裝即可:

pip install scrapyd-client

這個(gè)工具只需要安裝到本地計(jì)算機(jī)上,不需要安裝到云服務(wù)器上

啟動(dòng)Scrapyd

接下來需要在云服務(wù)器上啟動(dòng)Scrapyd。在默認(rèn)情況下,Scrapyd不能從外網(wǎng)訪問,為了讓它能夠被外網(wǎng)訪問,需要?jiǎng)?chuàng)建一個(gè)配置文件。除了bind_address這一項(xiàng)外,其他都可以保持默認(rèn)。bind_address這一項(xiàng)的值設(shè)定為當(dāng)前這臺(tái)云服務(wù)器的外網(wǎng)IP地址。配置文件放好以后,在終端或者CMD中輸入scrapyd并按Enter鍵,這樣Scrapyd就啟動(dòng)了。

scrapyd

此時(shí)打開瀏覽器,輸入“http://云服務(wù)器IP地址:6800”格式的地址就可以打開Scrapyd自帶的簡(jiǎn)陋網(wǎng)頁

部署爬蟲

Scrapyd啟動(dòng)以后,就可以開始部署爬蟲了。打開任意一個(gè)Scrapy的工程文件,可以看到在工程的根目錄中,Scrapy已經(jīng)自動(dòng)創(chuàng)建了一個(gè)scrapy.cfg文件,打開這個(gè)文件。現(xiàn)在需要把第10行的注釋符號(hào)去掉,并將IP地址改為Scrapyd所在云服務(wù)器的IP地址

最后,使用終端或者CMD進(jìn)入這個(gè)Scrapy工程的根目錄,執(zhí)行下面這一行命令部署爬蟲:

scrapyd-deploy

Mac OS和Linux系統(tǒng),啟動(dòng)/停止爬蟲

curl這個(gè)發(fā)起網(wǎng)絡(luò)請(qǐng)求的自帶工具

在上傳了爬蟲以后,就可以啟動(dòng)爬蟲了。對(duì)于Mac OS和Linux系統(tǒng),啟動(dòng)和停止爬蟲非常簡(jiǎn)單。要啟動(dòng)爬蟲,需要在終端輸入下面這一行格式的代碼。

curl http://云服務(wù)器IP地址:6800/schedule.json -d project=爬蟲工程名 -d spider=爬蟲名

如果爬蟲的運(yùn)行時(shí)間太長(zhǎng),希望提前結(jié)束爬蟲,那么可以使用下面格式的命令來實(shí)現(xiàn):

curl http://爬蟲服務(wù)器IP地址:6800/cancel.json -d project=工程名 -d job=爬蟲JOBID(在網(wǎng)頁上可以查詢到)

運(yùn)行以后,相當(dāng)于對(duì)爬蟲按下了Ctrl+C組合鍵的效果

Windows系統(tǒng),啟動(dòng)/停止爬蟲

沒有像Mac OS和Linux的終端一樣擁有curl這個(gè)發(fā)起網(wǎng)絡(luò)請(qǐng)求的自帶工具。但既然是發(fā)起網(wǎng)絡(luò)請(qǐng)求,那么只需要借助Python和requests就可以完成。

  • 使用requests發(fā)送請(qǐng)求啟動(dòng)爬蟲
  • 使用requests發(fā)送請(qǐng)求關(guān)閉爬蟲

在Python中執(zhí)行命令部署爬蟲

由于部署爬蟲的時(shí)候直接執(zhí)行scrapyd-deploy命令,所以如何使用Python來自動(dòng)化部署爬蟲呢?其實(shí)也非常容易。在Python里面使用os這個(gè)自帶模塊就可以執(zhí)行系統(tǒng)命令

批量部署

使用Python與requests的好處不僅在于可以幫助Windows實(shí)現(xiàn)控制爬蟲,還可以用來實(shí)現(xiàn)批量部署、批量控制爬蟲。

假設(shè)有一百臺(tái)云服務(wù)器,只要每一臺(tái)上面都安裝了Scrapyd,那么使用Python來批量部署并啟動(dòng)爬蟲所需要的時(shí)間不超過1min。

這里給出一個(gè)批量部署并啟動(dòng)爬蟲的例子,首先在爬蟲的根目錄下創(chuàng)建一個(gè)scrapy_template.cfg文件

權(quán)限管理

為了彌補(bǔ)Scrapyd沒有權(quán)限管理系統(tǒng)這一短板,就需要借助其他方式來對(duì)網(wǎng)絡(luò)請(qǐng)求進(jìn)行管控。帶權(quán)限管理的反向代理就是一種解決辦法。

Nginx的介紹

Nginx讀作Engine X,是一個(gè)輕量級(jí)的高性能網(wǎng)絡(luò)服務(wù)器、負(fù)載均衡器和反向代理。

為了解決Scrapyd的問題,需要用Nginx做反向代理。

正向代理與反向代理

所謂“反向代理”,是相對(duì)于“正向代理”而言的。前面章節(jié)所用到的代理是正向代理。正向代理幫助請(qǐng)求者(爬蟲)隱藏身份,爬蟲通過代理訪問服務(wù)器,服務(wù)器只能看到代理IP,看不到爬蟲;

反向代理幫助服務(wù)器隱藏身份。用戶只知道服務(wù)器返回的內(nèi)容,但不知道也不需要知道這個(gè)內(nèi)容是在哪里生成的。

使用Nginx來保護(hù)Scrapyd

使用Nginx反向代理到Scrapyd以后,Scrapyd本身只需要開通內(nèi)網(wǎng)訪問即可。

用戶訪問Nginx,Nginx再訪問Scrapyd,然后Scrapyd把結(jié)果返回給Nginx,Nginx再把結(jié)果返回給用戶。這樣只要在Nginx上設(shè)置登錄密碼,就可以間接實(shí)現(xiàn)Scrapyd的訪問管控了

Nginx的安裝

sudo apt-get install nginx

安裝好以后,需要考慮以下兩個(gè)問題。

  • 服務(wù)器是否有其他的程序占用了80端口。
  • 服務(wù)器是否有防火墻。

/etc/nginx/sites-available/default文件,將80全部改成81并保存

sudo systemctl restart nginx

配置反向代理

首先打開/etc/scrapyd/scrapyd.conf,把bind_address這一項(xiàng)重新改為127.0.0.1,并把http_port這一項(xiàng)改為6801。把Scrapyd設(shè)置為只允許內(nèi)網(wǎng)訪問,端口為6801

接下來配置Nginx,在/etc/nginx/sites-available文件夾下創(chuàng)建一個(gè)scrapyd.conf,其內(nèi)容為:

server {listen 6800;location / {proxy_pass http://127.0.0.1:6801/;auth_basic "Restricted";auth_basic_user_file /etc/nginx/conf.d/.htpasswd;}}

使用basic auth權(quán)限管理方法,對(duì)于通過授權(quán)的用戶,將它對(duì)6800端口的請(qǐng)求轉(zhuǎn)到服務(wù)器本地的6801端口。需要注意配置里面的記錄授權(quán)文件的路徑這一項(xiàng):auth_basic_user_file /etc/nginx/conf.d/.htpasswd

在后面會(huì)將授權(quán)信息的記錄文件放在/etc/nginx/conf.d/.htpasswd這個(gè)文件中。寫好這個(gè)配置以后,保存。

接下來,執(zhí)行下面的命令,在/etc/nginx/sites-enabled文件夾下創(chuàng)建一個(gè)軟連接:

sudo ln -s /etc/nginx/sites-available/scrapyd.conf /etc/nginx/sites-enabled/

軟連接創(chuàng)建好以后,需要生成賬號(hào)和密碼的配置文件。首先安裝apache2-utils軟件包:

sudo apt-get install apache2-utils

安裝完成apache2-utils以后,cd進(jìn)入/etc/nginx/conf.d文件夾,并執(zhí)行命令為用戶kingname生成密碼文件:

sudo htpasswd -c .htpasswd kingname

上面的命令會(huì)在/etc/nginx/conf.d文件夾下生成一個(gè).htpasswd的隱藏文件。有了這個(gè)文件,Nginx就能進(jìn)行權(quán)限驗(yàn)證了。

接下來重啟Nginx:

sudo systemctl restart nginx

重啟完成以后,啟動(dòng)Scrapyd,再在瀏覽器上訪問格式為“http://服務(wù)器IP:6800”的網(wǎng)址

配置Scrapy工程

由于為Scrapyd添加了權(quán)限管控,因此在12.2.1小節(jié)中涉及的部署爬蟲、啟動(dòng)/停止爬蟲的地方都要做一些小修改。

首先是部署爬蟲,為了讓scrapyd-deploy能成功地輸入密碼,需要修改爬蟲根目錄的scrapy.cfg文件,添加username和password兩項(xiàng),其中username對(duì)應(yīng)賬號(hào),password對(duì)應(yīng)密碼。

配置好scrapy.cfg以后,部署爬蟲的命令不變,還是進(jìn)入這個(gè)Scrapy工程的根目錄,執(zhí)行以下代碼即可:

scrapyd-deploy

使用curl啟動(dòng)/關(guān)閉爬蟲,只需要在命令上加上賬號(hào)參數(shù)即可。賬號(hào)參數(shù)為“-u 用戶名:密碼”。

所以,啟動(dòng)爬蟲的命令為:

curl http://45.76.110.210:6800/schedule.json -d project=工程名 -d spider=爬蟲名 -u kingname:genius停止爬蟲的命令為:```shell curl http://45.76.110.210:6800/cancel.json -d project=工程名 -d job=爬蟲JOBID-u kingname:genius

如果使用Python與requests編寫腳本來控制爬蟲,那么賬號(hào)信息可以作為POST方法的一個(gè)參數(shù),參數(shù)名為auth,值為一個(gè)元組,元組第0項(xiàng)為賬號(hào),第1項(xiàng)為密碼:

result = requests.post(start_url, data=start_data, auth=('kingname', 'genius')).text result = requests.post(end_url, data=end_data, auth=('kingname', 'genius')).text

分布式架構(gòu)介紹

在前面章節(jié)中已經(jīng)講到了把目標(biāo)放到Redis里面,然后讓多個(gè)爬蟲從Redis中讀取目標(biāo)再爬取的架構(gòu),這其實(shí)就是一種主—從式的分布式架構(gòu)。使用Scrapy,配合scrapy_redis,再加上Redis,也就實(shí)現(xiàn)了一個(gè)所謂的分布式爬蟲。

實(shí)際上,這種分布式爬蟲的核心概念就是一個(gè)中心結(jié)點(diǎn),也叫Master。它上面跑著一個(gè)Redis,所有的待爬網(wǎng)站的網(wǎng)址都在里面。其他云服務(wù)器上面的爬蟲(Slave)就從這個(gè)共同的Redis中讀取待爬網(wǎng)址。

分布式爬蟲架構(gòu)圖

只要能訪問這個(gè)Master服務(wù)器,并讀取Redis,那么其他服務(wù)器使用什么系統(tǒng)什么提供商都沒有關(guān)系。

例如,使用Ubuntu作為爬蟲的Master,用來做任務(wù)的派分。

使用樹莓派、Windows 10 PC和Mac來作為分布式爬蟲的Slave,用來爬取網(wǎng)站,并將結(jié)果保存到Mac上面運(yùn)行的MongoDB中。

其中,作為Master的Ubuntu服務(wù)器僅需要安裝Redis即可,它的作用僅僅是作為一個(gè)待爬網(wǎng)址的臨時(shí)中轉(zhuǎn),所以甚至不需要安裝Python。

在Mac、樹莓派和Windows PC中,需要安裝好Scrapy,并通過Scrapyd管理爬蟲。由于爬蟲會(huì)一直監(jiān)控Master的Redis,所以在Redis沒有數(shù)據(jù)的時(shí)候爬蟲處于待命狀態(tài)。

當(dāng)目標(biāo)被放進(jìn)了Redis以后,爬蟲就能開始運(yùn)行了。由于Redis是一個(gè)單線程的數(shù)據(jù)庫,因此不會(huì)出現(xiàn)多個(gè)爬蟲拿到同一個(gè)網(wǎng)址的情況。

如何選擇Master

嚴(yán)格來講,Master只需要能運(yùn)行Redis并且能被其他爬蟲訪問即可。但是如果能擁有一個(gè)公網(wǎng)IP則更好。這樣可以從世界上任何一個(gè)能訪問互聯(lián)網(wǎng)的地方訪問Master。但如果實(shí)在沒有云服務(wù)器,也并不是說一定得花錢買一個(gè),如果自己有很多臺(tái)計(jì)算機(jī),完全可以用一臺(tái)計(jì)算機(jī)來作為Master,其他計(jì)算機(jī)來做Slave。

Master也可以同時(shí)是Slave。在第11章的例子中,Scrapy和Redis是安裝在同一臺(tái)計(jì)算機(jī)中的。這臺(tái)計(jì)算機(jī)既是Master又是Slave。

Master一定要能夠被其他所有的Slave訪問。所以,如果所有計(jì)算機(jī)不在同一個(gè)局域網(wǎng),那么就需要想辦法弄到一臺(tái)具有公網(wǎng)IP的計(jì)算機(jī)或者云服務(wù)器。

在中國(guó),大部分情況下,電信運(yùn)營(yíng)商分配到的IP是內(nèi)網(wǎng)IP。在這種情況下,即使知道了IP地址,也沒有辦法從外面連進(jìn)來。

在局域網(wǎng)里面,因?yàn)榫钟蚓W(wǎng)共用一個(gè)出口,局域網(wǎng)內(nèi)的所有共用同一個(gè)公網(wǎng)IP。對(duì)網(wǎng)站來說,這個(gè)IP地址訪問頻率太高了,肯定不是人在訪問,從而被網(wǎng)站封鎖的可能性增大。而使用分布式爬蟲,不僅僅是為了提高訪問抓取速度,更重要的是降低每一個(gè)IP的訪問頻率,使網(wǎng)站誤認(rèn)為這是人在訪問。所以,如果所有的爬蟲確實(shí)都在同一個(gè)局域網(wǎng)共用一個(gè)出口的話,建議為每個(gè)爬蟲加上代理。

在實(shí)際生產(chǎn)環(huán)境中,最理想的情況是每一個(gè)Slave的公網(wǎng)IP都不一樣,這樣才能做到既能快速抓取,又能減小被反爬蟲機(jī)制封鎖的機(jī)會(huì)。

小結(jié)

本章主要介紹了Scrapy中間件的高級(jí)用法和爬蟲的批量部署。

使用中間件可以讓爬蟲專注于提取數(shù)據(jù),而像更換IP、獲取登錄Session等事情全部都交給中間件來做。這樣可以讓爬蟲本身的代碼更加簡(jiǎn)潔,也便于協(xié)同開發(fā)。

使用Scrapyd來部署爬蟲,可以實(shí)現(xiàn)遠(yuǎn)程開關(guān)爬蟲和批量部署爬蟲,從而實(shí)現(xiàn)分布式爬蟲。

第13章 爬蟲開發(fā)中的法律和道德問題

小結(jié)

  • 在爬蟲開發(fā)和數(shù)據(jù)采集的過程中,閱讀網(wǎng)站的協(xié)議可以有效發(fā)現(xiàn)并規(guī)避潛在的法律風(fēng)險(xiǎn)。
  • 爬蟲在爬取網(wǎng)站的時(shí)候控制頻率,善待網(wǎng)站,才能讓爬蟲運(yùn)行得更長(zhǎng)久。

總結(jié)

以上是生活随笔為你收集整理的Python爬虫开发从入门到实战的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。

日韩激情片在线观看 | 69av久久| 亚洲天堂毛片 | 婷婷丁香导航 | av大全在线| 性日韩欧美在线视频 | 日韩电影一区二区三区在线观看 | 在线看一区 | 1024手机基地在线观看 | 一本大道久久精品懂色aⅴ 五月婷社区 | 久久久国产99久久国产一 | 91看片网址 | 成人亚洲欧美 | 久久免费视频1 | 一级片视频在线 | 亚洲 欧美变态 另类 综合 | 日本久久久精品视频 | 日韩v在线91成人自拍 | 天天操天天干天天综合网 | 91成人短视频在线观看 | 国产日韩视频在线观看 | 天堂av在线| 中文字幕日本电影 | www.黄色片网站 | 久久蜜桃av | 久久免费视频一区 | 色综合久久88色综合天天免费 | 99久久久久久 | 国产精品视频线看 | 国产精品成人国产乱一区 | 午夜美女福利直播 | 日韩欧美精品在线 | 久久久伦理| 最新日本中文字幕 | 伊人超碰在线 | 国产精品国产精品 | 97超碰资源 | 亚洲欧美观看 | 欧美极品少妇xxxxⅹ欧美极品少妇xxxx亚洲精品 | 国产一区二区在线免费播放 | 五月天久久久久 | 麻豆久久精品 | 有码中文字幕在线观看 | 精品国产一二三四区 | 成人av电影在线观看 | 国产视频在线观看一区 | 久久精品成人欧美大片古装 | 青青草久草在线 | 狠狠干夜夜 | 婷婷在线五月 | 日韩一区二区三区高清在线观看 | av日韩av| 黄色1级大片 | 国产美女主播精品一区二区三区 | 欧美精彩视频在线观看 | 成人网在线免费视频 | av电影中文字幕在线观看 | 久久精品中文字幕少妇 | 成人免费视频播放 | 国产成年人av | 91精品综合在线观看 | 国产99久久 | a在线观看免费视频 | 国产一区二区三区免费在线 | 9999国产精品| 在线久草视频 | 9999在线观看 | 欧美精品一区二区三区四区在线 | 亚洲国产丝袜在线观看 | 亚洲国产成人久久 | 欧美韩日精品 | 亚洲精品在线视频观看 | 一区二区三区福利 | 国产成人综合图片 | 国产精品五月天 | 在线观看网站你懂的 | 久草com| 高潮久久久久久久久 | 亚洲国产片 | 黄色一级网 | www色av| 在线视频日韩精品 | 日本公乱妇视频 | 亚洲一区二区三区毛片 | 欧美无极色| 亚洲日韩欧美一区二区在线 | 黄色av免费看 | 伊人日日干 | 女人18精品一区二区三区 | 午夜av不卡 | 日韩mv欧美mv国产精品 | 五月婷婷久 | 特级黄色视频毛片 | 九九久 | 婷婷爱五月天 | 99久久婷婷国产综合亚洲 | 日本视频精品 | 97电院网手机版 | 8090yy亚洲精品久久 | 国产精品扒开做爽爽的视频 | 亚洲少妇久久 | 国内精品久久久久久久久久久久 | 男女激情免费网站 | 国外av在线 | 久久视频免费在线观看 | 欧美色道| 毛片网站免费在线观看 | 色噜噜色噜噜 | 天天操夜夜操天天射 | 国产视频黄 | 永久免费精品视频 | 特级a老妇做爰全过程 | 久草视频免费 | 精精国产xxxx视频在线播放 | 国产成人精品免费在线观看 | 日韩免费一区二区 | 婷婷播播网 | 久久精品欧美 | 免费网站看av片 | 五月香视频在线观看 | 人人爱人人射 | 免费看黄的视频 | 亚洲成年人在线播放 | 国产成人精品亚洲日本在线观看 | 亚洲砖区区免费 | 亚洲婷久久| 国产高清成人av | 在线观看国产一区二区 | www91在线 | 成人黄色视 | 在线视频电影 | 久久久久区 | 中文字幕一区二区三区四区久久 | 国产在线国产 | 99热99热| 中文字幕亚洲五码 | 亚洲经典在线 | 97看片吧| 欧美一区在线观看视频 | 在线亚洲成人 | 97福利| 日本高清dvd | 久久96国产精品久久99软件 | avlulu久久精品 | 18久久久久久 | 成人免费在线观看电影 | 99riav1国产精品视频 | 亚洲成av人影院 | 免费亚洲视频在线观看 | 成人在线播放视频 | 99久久精品无码一区二区毛片 | 欧美另类xxxxx | 亚洲一区二区三区四区精品 | 久久精品毛片基地 | 久久av影视| 久久久国产一区二区三区四区小说 | 日韩大片免费观看 | 婷婷精品国产一区二区三区日韩 | 黄色软件在线观看免费 | 97人人超碰在线 | 久久综合五月天 | 国内精品久久影院 | 久久一级片 | 色吊丝在线永久观看最新版本 | 成人黄色视 | 久久精品99久久 | 中文在线a在线 | 久久精品一级片 | 精品欧美一区二区在线观看 | 91九色蝌蚪 | 久草在线资源观看 | 狠狠的操你 | 精品不卡av | 精品少妇一区二区三区在线 | 久久国产免费视频 | 在线91精品 | av大片免费在线观看 | 美女露久久 | 色婷婷成人 | 麻豆视频一区 | 精品女同一区二区三区在线观看 | 精品在线一区二区三区 | av888.com| 狠狠色婷婷丁香六月 | 日韩电影精品一区 | 国产偷v国产偷∨精品视频 在线草 | 九九九视频在线 | 国产精品一区二区三区免费视频 | 五月香视频在线观看 | 欧美三级高清 | 亚洲精品一区二区18漫画 | 国产亚洲成人精品 | 成人久久久久久久久 | 日日碰夜夜爽 | 国产一区免费在线观看 | 亚洲欧美va | 国产成人精品日本亚洲999 | 国产精品成人久久 | 免费a现在观看 | av在线一级 | 久久久亚洲麻豆日韩精品一区三区 | 成人午夜免费剧场 | 婷婷色伊人 | 亚洲国产视频在线 | 在线视频观看成人 | 91免费国产在线观看 | 亚洲成人av在线电影 | 中文字幕免费高清 | 亚洲免费永久精品国产 | 精品二区久久 | 国产精品人成电影在线观看 | 中文字幕在线观看免费观看 | 在线观看自拍 | 97色狠狠 | 天天色天天射天天干 | 五月婷婷综合激情 | 日韩精选在线 | 国产精品嫩草影视久久久 | 97香蕉视频 | 欧美另类xxxxx | 黄p在线播放| 国产糖心vlog在线观看 | 精品美女久久久久 | 狠狠躁18三区二区一区ai明星 | 亚洲一区二区高潮无套美女 | 91麻豆国产 | 国产精品久久久久永久免费观看 | 日韩电影在线观看一区 | 日韩伦理片一区二区三区 | 亚洲高清免费在线 | 欧美一级乱黄 | 五月婷婷在线视频 | 天天爽人人爽 | 91福利免费 | 久久爱992xxoo| 日日夜夜操操操操 | 亚洲第二色 | 亚洲国产99 | 国精产品永久999 | 福利网址在线观看 | www.久久色| 国产麻豆精品传媒av国产下载 | 免费a视频在线观看 | 99久久超碰中文字幕伊人 | 国产999精品久久久影片官网 | 色偷偷888欧美精品久久久 | 二区三区精品 | 久久综合五月 | 国产精品国内免费一区二区三区 | 成人av在线亚洲 | 日本 在线 视频 中文 有码 | 麻豆精品视频在线观看免费 | 欧美精品第一 | 久草在线观| 13日本xxxxxⅹxxx20 | 夜添久久精品亚洲国产精品 | 午夜在线资源 | 午夜12点 | 91在线在线观看 | 六月色丁 | 91麻豆免费视频 | 欧美精品久久久久久久亚洲调教 | 色福利网 | 中国一级特黄毛片大片久久 | 久久精品国产免费观看 | 日韩在线在线 | 69性欧美 | 欧美精品在线观看 | 久久三级毛片 | www.狠狠操.com| 天天插天天色 | 国产精品自产拍在线观看蜜 | 久99久精品视频免费观看 | 久久中文字幕导航 | 天天综合天天做天天综合 | 在线看国产精品 | 色爱成人网 | 91豆花在线观看 | 亚洲九九精品 | 国产群p | 欧美另类美少妇69xxxx | 91福利免费| 在线国产一区 | 中文字幕色在线视频 | 深夜福利视频一区二区 | 国产福利免费看 | 黄污视频网站大全 | 日日夜夜网| 亚洲无人区小视频 | 国产成人a v电影 | 欧美成天堂网地址 | 91精品推荐 | 中文字幕在线高清 | 日本精品一区二区 | 国产一级片在线播放 | 日韩欧美精品在线 | 国产精品密入口果冻 | 人人添人人澡人人澡人人人爽 | 国产毛片在线 | 久久久精品欧美一区二区免费 | 91大神视频网站 | 国产精品黄色av | 国产精品1区2区 | 成人激情开心网 | 色丁香婷婷 | 中文字幕中文字幕在线中文字幕三区 | 中文字幕视频一区 | 国产日本在线播放 | 一级片色播影院 | 久久精品直播 | www.香蕉视频在线观看 | 日韩在线一二三区 | 国产亚洲精品久久久久久 | 国产1区2 | 亚洲国产最新 | 日韩美女一级片 | 91视频啪| 久久久久电影 | 亚洲性少妇性猛交wwww乱大交 | 久久99久久久久久 | 国产成人精品一区二三区 | 日本中文字幕视频 | 精品久久1| 最新影院 | 欧美日韩另类在线观看 | 婷婷久久网站 | 在线黄色av电影 | 一区二区精品视频 | 久久99国产综合精品免费 | 亚洲中字幕 | 久草视频在线免费 | 在线观看视频在线 | 久艹视频免费观看 | 久久99亚洲精品久久久久 | 久久伦理网 | 久久久久久久久久久综合 | 一区二区三区免费在线观看视频 | 久久黄色片子 | av 一区二区三区 | 中文字幕第一页在线视频 | 狠狠做六月爱婷婷综合aⅴ 日本高清免费中文字幕 | 在线观看国产麻豆 | 国产精品成人av电影 | 视频一区久久 | 国产精品一级视频 | 中文字幕一二三区 | 天天干天天干天天色 | 又黄又爽又色无遮挡免费 | 91香蕉国产在线观看软件 | 绯色av一区 | 日韩一区正在播放 | 欧美精品一区二区免费 | 日韩h在线观看 | 久久视频精品在线观看 | 激情网五月天 | 999在线观看视频 | 欧亚日韩精品一区二区在线 | 丁香亚洲 | 操操操天天操 | 欧美精品九九99久久 | www.久久色.com | 国产一区在线播放 | 日韩电影久久 | 中文字幕av在线不卡 | 久久人人爽人人 | 五月婷婷综合在线观看 | 亚洲 欧美 91 | 深夜免费福利网站 | 天天操天天色天天射 | 欧美精品久久天天躁 | 在线99视频 | 国产美女免费视频 | 成人av在线影院 | 亚洲一区二区精品视频 | 91麻豆国产福利在线观看 | 97超碰站| 国内免费久久久久久久久久久 | 日韩精品视频在线观看免费 | 日韩精品三区四区 | 日韩一二区在线 | 最新中文字幕在线资源 | 激情综合网色播五月 | 久久久久久久久综合 | 国产精品一区二区精品视频免费看 | 国产视频在线播放 | 69精品久久 | 99久久国产免费看 | 韩国av在线 | 亚洲精品综合一区二区 | 国产精品日韩高清 | 日韩在线观看你懂的 | 三级黄色免费片 | 国产剧情在线一区 | 99热免费在线 | 欧美性生活一级片 | 福利一区二区三区四区 | 国产精品 亚洲精品 | 久久精品国产亚洲精品2020 | 操操综合网| 99视频在线播放 | 天天天天天天操 | 久久久久久久久久免费 | 中文字幕一区二区三区视频 | 日本特黄特色aaa大片免费 | 91九色国产在线 | 欧美一区二区精品在线 | a黄色片 | 欧美日韩一级视频 | 亚洲 中文字幕av | 国产精品久久99综合免费观看尤物 | 丁香九月激情综合 | 日韩欧美综合在线视频 | 国产精品久久久久久久久久久杏吧 | 精品国产日本 | 亚洲视频免费在线观看 | 五月开心六月伊人色婷婷 | 91一区一区三区 | 欧美人人爱| 美女网站视频免费都是黄 | 狠狠干狠狠艹 | 日韩av高潮 | 日日碰狠狠添天天爽超碰97久久 | 四虎www | 欧美在线视频第一页 | 日日草视频 | 91精品亚洲影视在线观看 | 丁香九月婷婷综合 | 日韩免费视频播放 | 国产真实精品久久二三区 | 久久国产精品精品国产色婷婷 | 欧美成人精品三级在线观看播放 | 日本久久精品视频 | 三级免费黄色 | 日韩艹| 亚洲另类人人澡 | 午夜精品婷婷 | 精品一区二区免费在线观看 | 成人中文字幕+乱码+中文字幕 | 国产精品视频在线观看 | 欧美男同视频网站 | 免费黄a | 中文字幕 婷婷 | 天天操天天干天天玩 | 综合色久| 狠狠色狠狠色合久久伊人 | 麻豆国产精品永久免费视频 | 亚洲另类视频在线 | 丁香婷婷激情网 | 狠狠久久综合 | 91完整视频 | 中文字幕网址 | 国产一级一片免费播放放 | 国产精品久久久久婷婷 | 91色偷偷 | 伊人射 | 亚洲一二区视频 | 日本一区二区三区免费看 | 国产精品激情在线观看 | 亚洲国产激情 | 97色婷婷成人综合在线观看 | 一区二区视频欧美 | 一区二区三区 中文字幕 | 亚洲伊人av | 插插插色综合 | 午夜av影院 | 99精品一区二区三区 | 久久久高清一区二区三区 | 亚洲精品玖玖玖av在线看 | 久久深爱网| 午夜av不卡 | 国产在线观看国语版免费 | 五月天久久久 | 成人亚洲网 | 成人av直播| 免费看黄在线看 | 波多野结衣一区二区三区中文字幕 | 午夜91视频 | 亚洲欧美婷婷六月色综合 | 97超碰资源 | 欧美日韩在线播放 | 精品视频久久久 | 精品久久久久久久久久久院品网 | 国产成人一级电影 | 91精品一区二区在线观看 | 国产成人精品一区二区在线观看 | 日韩av午夜在线观看 | 色婷久久 | a视频在线观看 | 久草在线视频新 | 午夜视频在线观看一区 | 欧美在线99| 国产成人a亚洲精品 | av九九 | 香蕉影院在线观看 | 色网站在线免费观看 | 91福利视频在线 | 国产精品美女网站 | 黄色小说网站在线 | 91久久国产精品 | 免费看污的网站 | 成年人免费在线看 | 欧美午夜性生活 | 99国产精品免费网站 | 久久久999精品视频 国产美女免费观看 | 992tv在线| 天天操月月操 | 精品久久1 | 黄色一级在线视频 | 久久国产电影院 | 亚洲婷婷在线 | 国产夫妻av在线 | 激情欧美一区二区三区 | 亚洲网久久 | 国产午夜小视频 | 国产伦理久久精品久久久久_ | 九九热只有精品 | 五月婷婷久久丁香 | 91精品国产91久久久久久三级 | 亚洲激情校园春色 | 在线观看岛国 | 天天干,天天干 | 亚洲视频,欧洲视频 | 亚州人成在线播放 | 99国产视频在线 | 夜夜躁天天躁很躁波 | 国产精品99久久久久久宅男 | 亚洲区二区 | 五月天.com| 欧美成人播放 | 91亚洲网 | 特级a老妇做爰全过程 | 久久久久久久久久久福利 | 日韩不卡高清 | 亚洲综合视频在线播放 | 激情影院在线 | 欧美a√在线 | 日本三级久久 | 91精品影视 | 黄色一级片视频 | 最新av免费在线 | 亚洲国产色一区 | 亚洲丁香日韩 | 亚洲成色| 婷婷精品在线视频 | 黄色免费网 | 亚洲一区二区精品3399 | 九九综合九九综合 | av在线进入| 亚洲成免费 | 午夜久久久久 | 亚洲人成影院在线 | 国产小视频福利在线 | 一区二区三区四区久久 | 国产精品久久久久久吹潮天美传媒 | 永久免费精品视频 | 欧美久久久影院 | a级片久久久 | 狠狠做深爱婷婷综合一区 | japanesefreesex中国少妇 | 婷婷丁香色| 最新真实国产在线视频 | 亚洲免费不卡 | 精品理论片 | 国产激情电影综合在线看 | 97天天干 | 国产成人精品一区二区三区 | 成 人 黄 色 视频免费播放 | 黄色小网站在线观看 | 91精品在线观看视频 | 成人蜜桃| 91看片淫黄大片一级在线观看 | 日日夜夜天天久久 | 毛片网免费 | 日韩精品一区二区三区电影 | 国产精品日韩在线 | 欧美午夜a | 狠狠干 狠狠操 | 韩日三级在线 | 黄色成人91 | 四月婷婷在线观看 | 又湿又紧又大又爽a视频国产 | 五月婷婷激情网 | 中文字幕在线久一本久 | 天天操网 | 中文字幕字幕中文 | 91视视频在线直接观看在线看网页在线看 | 色综合咪咪久久网 | 亚洲精品免费观看视频 | 成人免费观看视频大全 | 六月丁香激情综合色啪小说 | 麻豆影视在线播放 | 欧美日韩a视频 | 成人一区二区在线观看 | 一区二区三区日韩在线 | 九色在线 | 国产一区二区三区免费观看视频 | 网站免费黄 | 色综合久久88色综合天天人守婷 | 亚洲一区二区三区毛片 | 人人射人人插 | 色五丁香 | 午夜视频欧美 | 在线黄网站 | 国产精品v a免费视频 | 欧美男女爱爱视频 | 99精品视频免费看 | 国产精品视频地址 | 精品视频99 | 国产精品一区二区三区在线播放 | 亚洲aⅴ免费在线观看 | 丰满少妇在线观看 | 国产亚洲精品xxoo | 国产一级久久 | 97超碰影视 | 亚洲不卡av一区二区三区 | 国产视频在线观看一区二区 | 久久久久国产成人精品亚洲午夜 | 在线观看完整版 | 亚洲va欧美va人人爽 | 午夜电影 电影 | 91av资源网 | 亚洲精品国产成人 | 丁香导航| 亚洲在线视频观看 | 精品欧美小视频在线观看 | 中文字幕激情 | 久草视频网| www天天操 | 国产精品免费视频久久久 | 91视频在线播放视频 | 99精品国产高清在线观看 | 欧美一级电影在线观看 | 久久久久久久国产精品视频 | 中文字幕一区二区三区四区视频 | 韩国av免费 | 91九色性视频| 亚洲精品一区二区三区高潮 | 亚洲婷婷伊人 | 久久伊人五月天 | 一区二区三区在线观看免费视频 | 91成人破解版 | 波多野结衣综合网 | 五月婷婷另类国产 | 国产又黄又硬又爽 | av免费网页 | 黄色网在线播放 | 久久不卡视频 | 手机av在线免费观看 | 精品亚洲一区二区 | 成人久久18免费网站 | 男女拍拍免费视频 | 九月婷婷色 | 免费网站看av片 | 日韩性xxxx| 99色网站| 久久精品中文字幕一区二区三区 | 91桃色在线观看视频 | 99精品国产成人一区二区 | 久久日本视频 | 最新国产精品拍自在线播放 | 精品麻豆入口免费 | av免费网站观看 | 久久精品国产免费观看 | 日韩欧美极品 | 日韩精品一区二区在线观看视频 | 国产夫妻性生活自拍 | 日韩免费看视频 | 国产99久久精品 | 综合色站| 在线观看视频日韩 | 欧美日本不卡 | 久久99热精品 | 欧美日韩精品电影 | 国产婷婷精品av在线 | 天堂麻豆 | 国产在线观看一 | a视频免费看| 国产 日韩 在线 亚洲 字幕 中文 | 伊人婷婷久久 | 天天天操操操 | 菠萝菠萝蜜在线播放 | 久久理论片 | 亚洲天堂香蕉 | 中文字幕在线观看视频一区二区三区 | 国产成人l区 | 超碰九九| 99中文字幕在线观看 | 中文字幕视频网站 | 成人动漫一区二区三区 | 国产精品久久久 | 就要干b | 成人av中文字幕 | 亚洲精品高清视频在线观看 | 国产不卡av在线播放 | 国产免费久久久久 | 欧美一区二区三区免费看 | 久久污视频 | 日韩在线中文字幕视频 | 五月婷影院 | 国产精品一区二区精品视频免费看 | 欧美高清视频不卡网 | 9色在线视频| 久久草网| 69国产成人综合久久精品欧美 | av色影院 | 国产成人1区| 成人a免费看| 91资源在线免费观看 | 黄污视频大全 | 久久在线影院 | 中文字幕精品一区久久久久 | 久久久久久久久艹 | 丁香在线观看完整电影视频 | 视频在线一区二区三区 | 国产成人免费av电影 | 免费看av在线 | 久久看片网站 | 国产精品免费久久久久久久久久中文 | 91麻豆精品国产91久久久无限制版 | 特黄特黄的视频 | 婷婷伊人五月天 | 黄色在线看网站 | 久久精品美女视频网站 | 操处女逼| 六月婷婷网 | 有码中文字幕 | 激情综合六月 | 久草视频99| 久久久久久久综合色一本 | 国产精品久久久av | 日韩成人免费电影 | 免费av试看| 91精品国产成 | 国产在线不卡一区 | 色婷婷骚婷婷 | 国产98色在线 | 日韩 | 久久久久成人精品免费播放动漫 | 国产不卡视频在线播放 | 99国内精品 | 国产黄色资源 | 日产乱码一二三区别免费 | 在线黄色国产 | 99热这里只有精品在线观看 | 中文字幕成人在线观看 | 亚洲男女精品 | 一区二区伦理电影 | 日韩欧美成 | 亚洲国产美女精品久久久久∴ | 操操操日日 | 在线观看岛国片 | 欧美一区二视频在线免费观看 | 日韩在线免费播放 | 亚洲高清视频在线播放 | 中文字幕亚洲字幕 | 激情五月av | 色狠狠干 | 色网站免费在线观看 | 国产无遮挡又黄又爽在线观看 | 色综合久久久久久久久五月 | 69欧美视频 | 久久97久久 | 国产高清免费观看 | 欧美视屏一区二区 | 午夜电影中文字幕 | 欧美激情综合五月色丁香小说 | 免费网站看v片在线a | 国产97视频 | free,性欧美 九九交易行官网 | 久久www免费人成看片高清 | 欧美日韩国产在线精品 | 国产aa精品 | 狠狠色丁香婷婷综合久久片 | 久久爽久久爽久久av东京爽 | 99麻豆久久久国产精品免费 | 国产福利91精品一区 | 黄色电影网站在线观看 | 亚洲欧洲国产精品 | 久久亚洲影院 | 国产精品久久久亚洲 | 操操操日日日干干干 | 国内视频在线 | 国产九九九精品视频 | 四虎视频| 日韩深夜在线观看 | 精品久久国产一区 | 国产精品久久久777 成人手机在线视频 | 成人黄色片免费看 | www.天天射.com| 91在线中字 | av免费福利 | 亚洲精品456在线播放第一页 | 国产91区 | 欧美日韩免费一区二区三区 | 国内精品中文字幕 | 精品久久久久久久久久 | 黄色一级在线免费观看 | 天堂av网址 | 狠狠干电影| 国产一区高清在线 | 最新影院| 波多野结衣久久资源 | 国产成人免费观看 | 久草视频在线资源站 | 免费又黄又爽 | 字幕网在线观看 | 97视频免费在线看 | 综合久久一本 | 中文字幕丝袜一区二区 | 免费看黄网站在线 | 日韩一片| 视频一区二区精品 | 国产中文字幕亚洲 | 在线观看aaa| 99视频国产精品免费观看 | 免费看黄色小说的网站 | 久久久综合九色合综国产精品 | 国产在线一区二区三区播放 | 人人超碰在线 | 亚洲开心激情 | av成人免费| 久久国产精品小视频 | 成人av在线电影 | 色婷婷99| 国产精彩视频一区二区 | 欧美日本不卡视频 | 久章草在线 | 国产一区二区电影在线观看 | 天天操狠狠操 | 国产 欧美 在线 | 国产精品久久久久久一二三四五 | 日本公妇在线观看高清 | 极品久久久久 | 一区二区精品 | 亚洲九九九在线观看 | 91久久国产自产拍夜夜嗨 | 超碰免费av | 97成人精品视频在线观看 | 欧美狠狠色 | 在线免费观看黄色 | 丁香激情婷婷 | 高潮久久久久久久久 | 日本aaa在线观看 | 成人午夜精品福利免费 | 特级毛片爽www免费版 | 亚洲精品在线免费播放 | 国产精品日韩久久久久 | 国产精品视频全国免费观看 | 97香蕉久久国产在线观看 | 久久成年人网站 | 久久电影国产免费久久电影 | 色婷婷色| 国产精品视频免费观看 | 国产人免费人成免费视频 | 免费黄色av电影 | 91av看片| 91九色老 | 成人午夜免费剧场 | 天天操天天舔天天爽 | 久久免费看a级毛毛片 | 国精产品一二三线999 | 在线观看免费福利 | 亚洲国产中文字幕在线观看 | 涩涩爱夜夜爱 | 91精品视频播放 | 亚洲最大免费成人网 | 2000xxx影视| 一区二区影院 | 麻豆国产网站入口 | 久久免费成人精品视频 | 中文字幕最新精品 | 久久综合九色综合网站 | 99免费精品视频 | 久草在线网址 | 1024手机基地在线观看 | 黄色特级一级片 | 色七七亚洲影院 | 日日操天天操夜夜操 | 久久免费国产视频 | 奇米影视777影音先锋 | 久久视频精品 | 日韩欧美一区二区三区视频 | 国产精品综合在线 | 91传媒在线 | 天天干天天综合 | 亚洲丝袜中文 | 韩国一区二区三区在线观看 | 国产91学生粉嫩喷水 | 亚洲午夜久久久综合37日本 | 欧美一区二区精美视频 | 婷婷 综合 色 | 精品国产欧美一区二区三区不卡 | 中文字幕在线观看第一页 | 黄色小说视频网站 | 在线国产激情视频 | 日韩乱码中文字幕 | 日韩理论电影网 | 中文欧美字幕免费 | aa级黄色大片 | 狠狠色丁香婷婷综合久久片 | 日韩免费av片| 欧美精品亚洲精品 | 99精品毛片| 中国黄色一级大片 | 中文字幕电影在线 | 久章草在线观看 | 黄网在线免费观看 | 国产精品久久久久久一区二区三区 | 成 人 黄 色 片 在线播放 | 日日草av| 日本动漫做毛片一区二区 | 中文字幕在线观看网址 | 在线免费色视频 | 国产资源在线免费观看 | 欧美精品久久久久久久久老牛影院 | 奇米影视四色8888 | 欧美日韩裸体免费视频 | 国产日韩视频在线观看 | 九九热在线观看视频 | 首页中文字幕 | 国产女教师精品久久av | 久久蜜桃av | 亚洲六月丁香色婷婷综合久久 | 91| 丰满少妇在线观看 | 精品久久久久久亚洲综合网站 | 日日夜夜91| 日韩av成人在线观看 | 成人九九视频 | 97超碰人人澡| 国产一区二区三区四区在线 | 视频高清 | 国产精品理论在线观看 | 久久久www成人免费毛片麻豆 | 91久草视频 | zzijzzij亚洲成熟少妇 | 欧美精品二 | 亚洲在线视频网站 | 色婷婷综合视频在线观看 | 国内精品久久久久久久久久久 | 久久五月婷婷丁香 | 国产一区高清在线 | 激情av在线资源 | 成人在线视频网 | 久久精品99久久久久久 | 久福利| 亚洲精品大全 | 欧美一区二区免费在线观看 | 国产高清视频免费观看 | 婷婷六月丁 | 999久久久国产精品 高清av免费观看 | 天天搞天天 | 国产精品久久久久免费观看 | 黄色软件视频网站 | 国产高清久久久 | 久久视了| 欧美日韩p片 | 91精品小视频 | 免费看污的网站 | 色视频在线观看免费 | 视频一区二区在线 | 欧美一二区在线 | 国产91在线观看 | 日韩视频区 | 成人在线视| 精品国产三级a∨在线欧美 免费一级片在线观看 | 91成版人在线观看入口 | 国产精品免费视频网站 | 在线免费成人 | 日韩免费视频播放 | 婷婷六月色 | 日韩大片在线观看 | 91精品免费在线观看 | 国产手机精品视频 | 国产麻豆视频在线观看 | 一级α片免费看 | 奇米导航 | 精品国产精品久久 | 91专区在线观看 | 91在线免费视频 | 精品九九九 | 国产精品精品国产婷婷这里av | 天天色欧美 | 国产精品视频免费在线观看 | 免费看污黄网站 | 在线视频 成人 | 国产精品成人a免费观看 | 91av手机在线 | 色婷婷综合在线 | 日本福利视频在线 | 国产在线va | 天天看天天干天天操 | 欧美二区在线播放 | 久草国产视频 | 久久狠狠干 | av免费看看 | 天天干婷婷 | 中文字幕一区二区三区久久蜜桃 | 91桃色在线观看视频 |