經過前面四章的學習,我們已經可以使用Requests庫、Beautiful Soup庫和Re庫,編寫基本的Python爬蟲程序了。那麼這一章就來學習一個專業的網路爬蟲框架--Scrapy。沒錯,是框架,而不是像前面介紹的函數功能庫。
Scrapy是一個快速、功能強大的網路爬蟲框架。
可能大家還不太了解什麼是框架,爬蟲框架其實是實現爬蟲功能的一個軟體結構和功能組件的集合。
簡而言之, Scrapy就是一個爬蟲程序的半成品,可以幫助用戶實現專業的網路爬蟲。
使用Scrapy框架,不需要你編寫大量的代碼,Scrapy已經把大部分工作都做好了,允許你調用幾句代碼便自動生成爬蟲程序,可以節省大量的時間。
當然,框架所生成的代碼基本是一致的,如果遇到一些特定的爬蟲任務時,就不如自己使用Requests庫搭建來的方便了。
PyCharm安裝
測試安裝:
出現框架版本說明安裝成功。
掌握Scrapy爬蟲框架的結構是使用好Scrapy的重中之重!
先上圖:
整個結構可以簡單地概括為: 「5+2」結構和3條數據流
5個主要模塊(及功能):
(1)控制所有模塊之間的數據流。
(2)可以根據條件觸發事件。
(1)根據請求下載網頁。
(1)對所有爬取請求進行調度管理。
(1)解析DOWNLOADER返回的響應--response。
(2)產生爬取項--scraped item。
(3)產生額外的爬取請求--request。
(1)以流水線方式處理SPIDER產生的爬取項。
(2)由一組操作順序組成,類似流水線,每個操作是一個ITEM PIPELINES類型。
(3)清理、檢查和查重爬取項中的HTML數據並將數據存儲到資料庫中。
2個中間鍵:
(1)對Engine、Scheler、Downloader之間進行用戶可配置的控制。
(2)修改、丟棄、新增請求或響應。
(1)對請求和爬取項進行再處理。
(2)修改、丟棄、新增請求或爬取項。
3條數據流:
(1):圖中數字 1-2
1:Engine從Spider處獲得爬取請求--request。
2:Engine將爬取請求轉發給Scheler,用於調度。
(2):圖中數字 3-4-5-6
3:Engine從Scheler處獲得下一個要爬取的請求。
4:Engine將爬取請求通過中間件發送給Downloader。
5:爬取網頁後,Downloader形成響應--response,通過中間件發送給Engine。
6:Engine將收到的響應通過中間件發送給Spider處理。
(3):圖中數字 7-8-9
7:Spider處理響應後產生爬取項--scraped item。
8:Engine將爬取項發送給Item Pipelines。
9:Engine將爬取請求發送給Scheler。
任務處理流程:從Spider的初始爬取請求開始爬取,Engine控制各模塊數據流,不間斷從Scheler處獲得爬取請求,直至請求為空,最後到Item Pipelines存儲數據結束。
作為用戶,只需配置好Scrapy框架的Spider和Item Pipelines,也就是數據流的入口與出口,便可完成一個爬蟲程序的搭建。Scrapy提供了簡單的爬蟲命令語句,幫助用戶一鍵配置剩餘文件,那我們便來看看有哪些好用的命令吧。
Scrapy採用命令行創建和運行爬蟲
PyCharm打開Terminal,啟動Scrapy:
Scrapy基本命令行格式:
具體常用命令如下:
下面用一個例子來學習一下命令的使用:
1.建立一個Scrapy爬蟲工程,在已啟動的Scrapy中繼續輸入:
執行該命令,系統會在PyCharm的工程文件中自動創建一個工程,命名為pythonDemo。
2.產生一個Scrapy爬蟲,以教育部網站為例http://www.moe.gov.cn:
命令生成了一個名為demo的spider,並在Spiders目錄下生成文件demo.py。
命令僅用於生成demo.py文件,該文件也可以手動生成。
觀察一下demo.py文件:
3.配置產生的spider爬蟲,也就是demo.py文件:
4.運行爬蟲,爬取網頁:
如果爬取成功,會發現在pythonDemo下多了一個t20210816_551472.html的文件,我們所爬取的網頁內容都已經寫入該文件了。
以上就是Scrapy框架的簡單使用了。
Request對象表示一個HTTP請求,由Spider生成,由Downloader執行。
Response對象表示一個HTTP響應,由Downloader生成,有Spider處理。
Item對象表示一個從HTML頁面中提取的信息內容,由Spider生成,由Item Pipelines處理。Item類似於字典類型,可以按照字典類型來操作。
❷ 如何python 中運行scapy shell
啟用shell
可以使用如下命令啟用shell
[python] view plain
scrapy shell <url>
其中<url>就是你想抓取的頁面url
使用shell
Scrapy shell可以看成是一個內置了幾個有用的功能函數的python控制台程序。
功能函數
shelp() - 輸出一系列可用的對象和函數
fetch(request_or_url)-從給定的url或既有的request請求對象重新生成response對象,並更新原有的相關對象
view(response)-使用瀏覽器打開原有的response對象(換句話說就是html頁面)
Scrapy 對象
使用Scrapy shell下載指定頁面的時候,會生成一些可用的對象,比如Response對象和Selector對象(Html和XML均適用)
這些可用的對象有:
crawler - 當前的Crawler對象
spider
request - 最後獲取頁面的請求對象
response - 一個包含最後獲取頁面的響應對象
sel - 最新下載頁面的Selector對象
settings - 當前的Scrapy settings
Scrapy shell例子
以我的個人博客作為測試:http://blog.csdn.net/php_fly
首先,我們啟動shell
[python] view plain
scrapy shell http://blog.csdn.net/php_fly --nolog
以上命令執行後,會使用Scrapy downloader下載指定url的頁面數據,並且列印出可用的對象和函數列表
[python] view plain
[s] Available Scrapy objects:
[s] crawler <scrapy.crawler.Crawler object at 0x0000000002AEF7B8>
[s] item {}
[s] request <GET http://blog.csdn.net/php_fly>
[s] response <200 http://blog.csdn.net/php_fly>
[s] sel <Selector xpath=None data=u'<html xmlns="http://www.w3.org/1999/xhtm'>
[s] settings <CrawlerSettings mole=None>
[s] spider <Spider 'default' at 0x4cdb940>
[s] Useful shortcuts:
[s] shelp() Shell help (print this help)
[s] fetch(req_or_url) Fetch request (or URL) and update local objects
[s] view(response) View response in a browser
獲取曾是土木人博客的文章列表超鏈接
[python] view plain
In [9]: sel.xpath("//span[@class='link_title']/a/@href").extract()
Out[9]:
[u'/php_fly/article/details/19364913',
u'/php_fly/article/details/18155421',
u'/php_fly/article/details/17629021',
u'/php_fly/article/details/17619689',
u'/php_fly/article/details/17386163',
u'/php_fly/article/details/17266889',
u'/php_fly/article/details/17172381',
u'/php_fly/article/details/17171985',
u'/php_fly/article/details/17145295',
u'/php_fly/article/details/17122961',
u'/php_fly/article/details/17117891',
u'/php_fly/article/details/14533681',
u'/php_fly/article/details/13162011',
u'/php_fly/article/details/12658277',
u'/php_fly/article/details/12528391',
u'/php_fly/article/details/12421473',
u'/php_fly/article/details/12319943',
u'/php_fly/article/details/12293587',
u'/php_fly/article/details/12293381',
u'/php_fly/article/details/12289803']
修改scrapy shell的請求方式:
[python] view plain
>>> request = request.replace(method="POST")
>>> fetch(request)
[s] Available Scrapy objects:
[s] crawler <scrapy.crawler.Crawler object at 0x1e16b50>
...
從Spider中調用Scrapy shell
在爬蟲運行過程中,有時需要檢查某個響應是否是你所期望的。
這個需求可以通過scrapy.shell.inspect_response函數進行實現
以下是一個關於如何從spider中調用scrapy shell的例子
[python] view plain
from scrapy.spider import Spider
class MySpider(Spider):
name = "myspider"
start_urls = [
"http://example.com",
"http://example.org",
"http://example.net",
]
def parse(self, response):
# We want to inspect one specific response.
if ".org" in response.url:
from scrapy.shell import inspect_response
inspect_response(response)
# Rest of parsing code.
當你啟動爬蟲的時候,控制台將列印出類似如下的信息
[python] view plain
2014-02-20 17:48:31-0400 [myspider] DEBUG: Crawled (200) <GET http://example.com> (referer: None)
2014-02-20 17:48:31-0400 [myspider] DEBUG: Crawled (200) <GET http://example.org> (referer: None)
[s] Available Scrapy objects:
[s] crawler <scrapy.crawler.Crawler object at 0x1e16b50>
...
>>> response.url
'http://example.org'
注意:當Scrapy engine被scrapy shell佔用的時候,Scrapy shell中的fetch函數是無法使用的。 然而,當你退出Scrapy shell的時候,蜘蛛將從停止的地方繼續爬行
❸ 如何在scrapy框架下,用python實現爬蟲自動跳轉頁面來抓去網頁內容
Scrapy是一個用Python寫的Crawler Framework,簡單輕巧,並且非常方便。Scrapy使用Twisted這個非同步網路庫來處理網路通信,架構清晰,並且包含了各種中間件介面,可以靈活地完成各種需求。Scrapy整體架構如下圖所示:
根據架構圖介紹一下Scrapy中的各大組件及其功能:
Scrapy引擎(Engine):負責控制數據流在系統的所有組建中流動,並在相應動作發生觸發事件。
調度器(Scheler):從引擎接收Request並將它們入隊,以便之後引擎請求request時提供給引擎。
下載器(Downloader):負責獲取頁面數據並提供給引擎,而後提供給Spider。
Spider:Scrapy用戶編寫用於分析Response並提取Item(即獲取到的Item)或額外跟進的URL的類。每個Spider負責處理一個特定(或一些網站)。
Item Pipeline:負責處理被Spider提取出來的Item。典型的處理有清理驗證及持久化(例如存儲到資料庫中,這部分後面會介紹存儲到MySQL中,其他的資料庫類似)。
下載器中間件(Downloader middlewares):是在引擎即下載器之間的特定鉤子(special hook),處理Downloader傳遞給引擎的Response。其提供了一個簡便的機制,通過插入自定義代碼來擴展Scrapy功能(後面會介紹配置一些中間並激活,用以應對反爬蟲)。
Spider中間件(Spider middlewares):是在引擎及Spider之間的特定鉤子(special hook),處理Spider的輸入(response)和輸出(Items即Requests)。其提供了一個簡便的機制,通過插入自定義的代碼來擴展Scrapy功能。
❹ python爬蟲-35-scrapy實操入門,一文帶你入門,保姆級教程
如果在 windows 系統下,提示這個錯誤 MoleNotFoundError: No mole named 'win32api' ,那麼使用以下命令可以解決: pip install pypiwin32 。
示例如下:
命令:
示例如下:
創建完畢之後可以看下具體創建了什麼文件;
我們使用 pycharm 打開看下;
scrapy 爬蟲項目中每個文件的作用如下:
------ 「運維家」 ------
------ 「運維家」 ------
------ 「運維家」 ------
linux系統下,mknodlinux,linux目錄寫許可權,大白菜能安裝linux嗎,linux系統創建文件的方法,領克linux系統怎麼裝軟體,linux文本定位;
ocr識別linux,linux錨定詞尾,linux系統使用記錄,u盤有linux鏡像文件,應屆生不會Linux,linux內核64位,linux自啟動管理服務;
linux計算文件夾大小,linux設備名稱有哪些,linux能用的虛擬機嗎,linux系統進入不了命令行,如何創建kalilinux,linux跟so文件一樣嗎。
❺ python爬蟲的工作步驟
當前處於一個大數據的時代,一般網站數據來源有二:網站用戶自身產生的數據和網站從其他來源獲取的數據,今天要分享的是如何從其他網站獲取你想要的數據。
目前最適合用於寫爬蟲的語言是python,python中最受歡迎的爬蟲框架是scrapy,本文圍繞scrapy來展開講解爬蟲是怎麼工作的。
1.如下圖所示,爬蟲從編寫的spider文件中的start_urls開始,這個列表中的url就是爬蟲抓取的第一個網頁,它的返回值是該url對應網頁的源代碼,我們可以用默認的parse(self,response)函數去列印或解析這個源代碼
2.我們獲取到源代碼之後,就可以從網頁源代碼中找到我們想要的信息或需要進一步訪問的url,提取信息這一步,scrapy中集成了xpath,正則(re),功能十分強大,提取到信息之後會通過yield進入到中間件當中。
中間件包括爬蟲中間件和下載中間件,爬蟲中間件主要用於設置處理爬蟲文件中的代碼塊,下載中間件主要用於判斷爬蟲進入網頁前後的爬取狀態,在此中間件中,你可以根據爬蟲的返回狀態去做進一步判斷。
最後我們將yield過來的item,即就是我們想要的數據會在pipeline.py文件中進行處理,存入資料庫,寫入本地文件,都可以在這里進行,另外,為了減少代碼冗餘,建議所有與設置參數有關的參數,都寫在settings.py中去
❻ 如何用Python爬取搜索引擎的結果
我選取的是爬取網路知道的html 作為我的搜索源數據,目前先打算做網頁標題的搜索,選用了 Python 的 scrapy 庫來對網頁進行爬取,爬取網頁的標題,url,以及html,用sqlist3來對爬取的數據源進行管理。
爬取的過程是一個深度優先的過程,設定四個起始 url ,然後維護一個資料庫,資料庫中有兩個表,一個 infoLib,其中存儲了爬取的主要信息:標題,url ,html;另一個表為urlLib,存儲已經爬取的url,是一個輔助表,在我們爬取每個網頁前,需要先判斷該網頁是否已爬過(是否存在urlLib中)。在數據存儲的過程中,使用了SQL的少量語法,由於我之前學過 MySQL ,這塊處理起來比較駕輕就熟。
深度優先的網頁爬取方案是:給定初始 url,爬取這個網頁中所有 url,繼續對網頁中的 url 遞歸爬取。代碼逐段解析在下面,方便自己以後回顧。
1.建一個 scrapy 工程:
關於建工程,可以參看這個scrapy入門教程,通過運行:
[python] view plain
scrapy startproject ***
在當前目錄下建一個scrapy 的項目,然後在 spiders 的子目錄下建立一個 .py文件,該文件即是爬蟲的主要文件,注意:其中該文件的名字不能與該工程的名字相同,否則,之後調用跑這個爬蟲的時候將會出現錯誤,見ImportError。
2.具體寫.py文件:
[python] view plain
import scrapy
from scrapy import Request
import sqlite3
class rsSpider(scrapy.spiders.Spider): #該類繼承自 scrapy 中的 spider
name = "" #將該爬蟲命名為 「知道」,在執行爬蟲時對應指令將為: scrapy crawl
#download_delay = 1 #只是用於控制爬蟲速度的,1s/次,可以用來對付反爬蟲
allowed_domains = ["..com"] #允許爬取的作用域
url_first = 'http://..com/question/' #用於之後解析域名用的短字元串
start_urls = ["http://..com/question/647795152324593805.html", #python
"http://..com/question/23976256.html", #database
"http://..com/question/336615223.html", #C++
"http://..com/question/251232779.html", #operator system
"http://..com/question/137965104.html" #Unix programing
] #定義初始的 url ,有五類知道起始網頁
#add database
connDataBase = sqlite3.connect(".db") #連接到資料庫「.db」
cDataBase = connDataBase.cursor() #設置定位指針
cDataBase.execute('''''CREATE TABLE IF NOT EXISTS infoLib
(id INTEGER PRIMARY KEY AUTOINCREMENT,name text,url text,html text)''')
#通過定位指針操作資料庫,若.db中 infoLib表不存在,則建立該表,其中主鍵是自增的 id(用於引擎的docId),下一列是文章的標題,然後是url,最後是html
#url dataBase
cDataBase.execute('''''CREATE TABLE IF NOT EXISTS urlLib
(url text PRIMARY KEY)''')
#通過定位指針操作資料庫,若.db中urlLib表不存在,則建立該表,其中只存了 url,保存已經爬過的url,之所以再建一個表,是猜測表的主鍵應該使用哈希表存儲的,查詢速度較快,此處其實也可以用一個外鍵將兩個表關聯起來
2. .py文件中的parse函數:
.py文件中的parse函數將具體處理url返回的 response,進行解析,具體代碼中說明:
[python] view plain
def parse(self,response):
pageName = response.xpath('//title/text()').extract()[0] #解析爬取網頁中的名稱
pageUrl = response.xpath("//head/link").re('href="(.*?)"')[0] #解析爬取網頁的 url,並不是直接使用函數獲取,那樣會夾雜亂碼
pageHtml = response.xpath("//html").extract()[0] #獲取網頁html
# judge whether pageUrl in cUrl
if pageUrl in self.start_urls:
#若當前url 是 start_url 中以一員。進行該判斷的原因是,我們對重復的 start_url 中的網址將仍然進行爬取,而對非 start_url 中的曾經爬過的網頁將不再爬取
self.cDataBase.execute('SELECT * FROM urlLib WHERE url = (?)',(pageUrl,))
lines = self.cDataBase.fetchall()
if len(lines): #若當前Url已經爬過
pass #則不再在資料庫中添加信息,只是由其為跟繼續往下爬
else: #否則,將信息爬入資料庫
self.cDataBase.execute('INSERT INTO urlLib (url) VALUES (?)',(pageUrl,))
self.cDataBase.execute("INSERT INTO infoLib (name,url,html) VALUES (?,?,?)",(pageName,pageUrl,pageHtml))
else: #此時進入的非 url 網頁一定是沒有爬取過的(因為深入start_url之後的網頁都會先進行判斷,在爬取,在下面的for循環中判斷)
self.cDataBase.execute('INSERT INTO urlLib (url) VALUES (?)',(pageUrl,))
self.cDataBase.execute("INSERT INTO infoLib (name,url,html) VALUES (?,?,?)",(pageName,pageUrl,pageHtml))
self.connDataBase.commit() #保存資料庫的更新
print "-----------------------------------------------" #輸出提示信息,沒啥用
for sel in response.xpath('//ul/li/a').re('href="(/question/.*?.html)'): #抓出所有該網頁的延伸網頁,進行判斷並對未爬過的網頁進行爬取
sel = "http://..com" + sel #解析出延伸網頁的url
self.cDataBase.execute('SELECT * FROM urlLib WHERE url = (?)',(sel,)) #判斷該網頁是否已在資料庫中
lines = self.cDataBase.fetchall()
if len(lines) == 0: #若不在,則對其繼續進行爬取
yield Request(url = sel, callback=self.parse)