爬取《糗事百科》-基礎知識篇
一、scrapy簡介
1、scrapy python的爬蟲框架,非常出名,我們此處學用法,實現功能即可。有興趣可以下載源碼、理解,底層使用了多進程、多線程、隊列等技術。
2、安裝:pip installscrapy
注意如果出錯:
building 'twisted.test.raiser' extension
error: Microsoft Visual C++ 14.0 is required. Get it with"Microsoft Visual C++ Build Tools": http://landinghub.visualstudio.com/visual-cpp-build-tools
解決方案:
http://www.lfd.uci.edu/~gohlke/pythonlibs/#twisted
下載twisted對應版本的whl文件(如我的Twisted-17.5.0-cp36-cp36m-win_amd64.whl),cp後面是python版本,amd64代表64位,運行命令:
pip install C:\Users\Downloads\Twisted-17.5.0-cp36-cp36m-win_amd64.whl
3、框架的介紹:
由5部分組成
① 引擎
② 下載器(負責下載)、
③ spiders(爬蟲文件)、
④ 調度器(調度的、爬蟲、給你一個url、爬完這個需要再去提取指定的url接着爬、調度器統一分發、生成一個請求對象,看讓誰發送這個請求對象)
⑤ 管道(pipeline)
我們的代碼寫到spider與管道中,spider裏面實現內容解析、鏈接提取(比如爬取內容、不只爬取第一頁內容,每頁鏈接不一樣);管道:決定數據是保存到mysql、文件、還是mongodb中。
4、scrapy工作原理:
見圖片:
先給個起始url,在spiders代碼裏放着,引擎會將起始url要過來,不做實際的工作,扔給調度器,調度器有個隊列,負責調度,如果需要下載,出隊給引擎,引擎不負責下載,扔給下載器,從互聯網把數據下載下來,會將數據再扔給引擎,引擎將數據給spiders,spiders裏面有解析內容的代碼,解析時候會有你想要的數據,存放到一個字典中,(不僅有數據。還會有其他的url)總之,解析完之後有兩種結果,url與數據,如果是數據,扔給引擎,引擎扔給管道,管道處理數據,存到哪裏?mysql?mongodb?如果是url,就會給調度器,再重複上述的步驟。
注意:
爬蟲核心:都在spiders裏面;
其他的 扔出去系統都會給處理的;
管道里面也是需要自己寫的;
調度器裏面也不需要自行編寫。出隊是系統決定的;
5、scrpy簡單使用
(1)創建項目:
在當前文件夾 打開超級終端
scrapy startproject firstblood
(scrapy路徑、還有包都在此路徑放着,你可以開啓指令開始爬蟲 cd進來,然後看下文)
*認識目錄結構:(*爲你需要打交道的文件)
firstblood
firstblood(真正的項目文件)
__pycache__(緩存文件)
spiders(爬蟲文件存放的位置)
__pycache__
__init__.py
lala.py(爬蟲文件、涉及文件的解析*)
__int__.py(包的標誌)
items.py(定義數據結構的的地方*)
middlewares.py(中間件)
pipelines.py(管道文件*)
settings.py(配置文件*)
scrapy.cfg(不用管)
(2)生成爬蟲文件
cd firstblood
scrapy genspider qiubaiwww.qiushibaike.com
qiubai:(爬蟲的名字)
www.qiushibaike.com:(爬取的域名)
會生成一個qiubai.py文件:
# -*- coding: utf-8 -*-
import scrapy
class QiubaiSpider(scrapy.Spider):
# 爬蟲的名字
name = 'qiubai'
# 允許的域名, 是一個列表,裏面可以放多個,一般都做限制
allowed_domains = ['www.qiushibaike.com', 'www.baidu.com']
# 起始url,是一個列表
start_urls = ['https://www.qiushibaike.com/']
# 解析函數,重寫這個方法,發送請求之後,響應來了就會調用這個方法,函數有一個參數response就是響應內容,該函數對返回值有一個要求,必須返回可迭代對象
def parse(self, response):
pass
class QiubaiSpider()
1爬蟲的名字
2允許的域名(多了一個限制,只爬取此域名下,不限制的話就是全爬取。如果域名比較多,此是一個列表,加逗號,往後接着寫域名)
3起始url(從哪兒開始爬取)
4 def parse
(解析函數,寫解析的代碼,發送的請求,響應過來之後,就在這裏解析,重寫這個方法,方法名不能改變,在這個方法中,響應就是傳個參數,response(就是響應內容),會自動調用,不用再手動寫,該函數對返回值有一個要求,就是返回可迭代對象)
*認識response對象
程序是如何跑起來的:
指令模式:
cd firstblood
firstblood
cd spiders
scrpycrawl qiubai
運行之後、有三處錯誤:
1.win32,注意版本
2.取消遵從robots協議 settings.py 在第22行
3.U-A頭部信息改一下,粘個headers在後面。在第19行
print(response.text)字符串類型
print(response.body)打印的字節類型
xpath():scrapy內部已經集成了xpath,直接使用即可,但是與原生的稍微有不同,後續會展示。
(3)執行輸出指定格式
scrapycrawl qiubai -o qiubai.json
scrapycrawl qiubai -o qiubai.xml
scrapycrawl qiubai -o qiubai.csv
【注】你輸出爲csv的時候,中間估計有空行,自己百度一下解決掉即可
二、scrapy shell
1、scrapy shell是什麼?
是一個調試工具,常用來調試xpath對不對。
2、安裝依賴:pip installipython
更加智能的交互環境可以通過tab提示內容
終端下任意位置,輸入如下指令:
scrapyshell 域名
3、屬性
response.url 請求的url
response.body字節類型
response.text
response.status響應狀態碼
response.headers響應頭
方法:xpath()提取出來的都是selector對象,需要進行extract()一下,然後再提取出來字符串
css():根據選擇器進行獲取指定的內容
示例:
ret=response.css('#content-left>div?.authorimg::attr(src)')
ret=response.css('#content-left'>div>.authorh2::text')
ret[0].extract()
selector對象
是scrapy自己封裝的一個對象,不論你上面通過xpath還是css,獲取到的都是這個對象
xpath()
css()
extract():將對象直接轉化爲字符串
extract_first():功能就等同於
extract_first()==[0].extract()=extract()[0]
如果xpath或者css寫錯了,返回一個空列表,通過後兩種方式就會報錯,但是通過extract_first()獲取,就會獲取none
item對象
爬取數據的時候,第一步就是要定義數據結構,在item.py中定義,通過這個類創建的對象十分特殊,類似字典,字典怎麼用,它就怎麼用,這個對象可以快速地轉換爲字典
回到ipthon輸入:
classPerson(scrapy.Item)(繼承這個類)
name=scray.Field()
age=scray.Field()
p=Person()(創建一個對象)
p['name']='goudan'(賦值)
p['age']=20
p['name']打印
p['age']
type(p)
d=dict(p)(轉化爲字典)
三、yield item和請求
1、yield是什麼意思?
deftest():
lt=[]
forx in range(1,11):
lt.append(x)
returnlt
如果寫100個,1000個,一下生成1000個,寫到列表中,都會顯示出來,這樣資源浪費,所以就引入了生成器。生成器,不是保存的數據,而是保存一個算法,用到的時候,直接調用,再給你生成。
def demo():
forx in range(1,11):
yieldx
a=demo()
print(a)
此時demo就不再是個函數 a=demo() print(a)就是一個生成器
print(next(a))取出第一個數據
print(next(a))
print(next(a))
print(next(a))
print(next(a))
....
print(next(a))到第11個再取就會報錯。
也可以遍歷:
for x in a:
print(x)
defdemo():
for x in range(1,11):
yield x
print'嘻嘻嘻'
yield '哈哈哈'
如果是print(next(a)),則只會打印一個1,嘻嘻嘻不會打印,只有打印下一個的時候,嘻嘻嘻纔會打印
函數中可以出現yield,證明這個函數是生成器,可以有多個yield
....
print(next(a))到第11個再取就會報錯。