python網絡爬蟲(14)使用Scrapy搭建爬蟲框架

python網絡爬蟲(14)使用Scrapy搭建爬蟲框架
閱讀目錄

目的意義
說明
創建scrapy工程
一些介紹說明
創建爬蟲模塊-下載
強化爬蟲模塊-解析
強化爬蟲模塊-包裝數據
強化爬蟲模塊-翻頁
強化爬蟲模塊-存儲
強化爬蟲模塊-圖像下載保存
啓動爬蟲
修正
目的意義
爬蟲框架也許能簡化工作量,提高效率等。scrapy是一款方便好用,拓展方便的框架。

本文將使用scrapy框架,示例爬取自己博客中的文章內容。

說明
學習和模仿來源:https://book.douban.com/subject/27061630/

創建scrapy工程
首先當然要確定好,有沒有完成安裝scrapy。在windows下,使用pip install scrapy,慢慢等所有依賴和scrapy安裝完畢即可。然後輸入scrapy到cmd中測試。

建立工程使用scrapy startproject myTestProject,會在工程下生成文件。

一些介紹說明
在生成的文件中,

創建爬蟲模塊-下載
在路徑./myTestProject/spiders下,放置用戶自定義爬蟲模塊,並定義好name,start_urls,parse()。

如在spiders目錄下建立文件CnblogSpider.py,並填入以下:

1
2
3
4
5
6
import scrapy
class CnblogsSpider(scrapy.Spider):

name="cnblogs"
start_urls=["https://www.cnblogs.com/bai2018/default.html?page=1"]
def parse(self,response):
    pass

在cmd中,切換到./myTestProject/myTestProject下,再執行scrapy crawl cnblogs(name)測試,觀察是否報錯,響應代碼是否爲200。其中的parse中參數response用於解析數據,讀取數據等。

強化爬蟲模塊-解析
在CnblogsSpider類中的parse方法下,添加解析功能。通過xpath、css、extract、re等方法,完成解析。

調取元素審查分析以後添加,成爲以下代碼:

1
2
3
4
5
6
7
8
9
10
11
12
13
import scrapy
class CnblogsSpider(scrapy.Spider):

name="cnblogs"
start_urls=["https://www.cnblogs.com/bai2018/"]
def parse(self,response):
    papers=response.xpath(".//*[@class='day']")
    for paper in papers:
        url=paper.xpath(".//*[@class='postTitle']/a/@href").extract()
        title=paper.xpath(".//*[@class='postTitle']/a/text()").extract()
        time=paper.xpath(".//*[@class='dayTitle']/a/text()").extract()
        content=paper.xpath(".//*[@class='postCon']/div/text()").extract()
        print(url,title,time,content)
    pass

找到頁面中,class爲day的部分,然後再找到其中各個部分,提取出來,最後通過print方案輸出用於測試。

在正確的目錄下,使用cmd運行scrapy crawl cnblogs,完成測試,並觀察顯示信息中的print內容是否符合要求。

強化爬蟲模塊-包裝數據
包裝數據的目的是存儲數據。scrapy使用Item類來滿足這樣的需求。

框架中的items.py用於定義存儲數據的Item類。

在items.py中修改MytestprojectItem類,成爲以下代碼:

1
2
3
4
5
6
7
8
9
import scrapy
class MytestprojectItem(scrapy.Item):

# define the fields for your item here like:
# name = scrapy.Field()
url=scrapy.Field()
time=scrapy.Field()
title=scrapy.Field()
content=scrapy.Field()
pass

然後修改CnblogsSpider.py,成爲以下內容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import scrapy
from myTestProject.items import MytestprojectItem
class CnblogsSpider(scrapy.Spider):

name="cnblogs"
start_urls=["https://www.cnblogs.com/bai2018/"]
def parse(self,response):
    papers=response.xpath(".//*[@class='day']")
    for paper in papers:
        url=paper.xpath(".//*[@class='postTitle']/a/@href").extract()
        title=paper.xpath(".//*[@class='postTitle']/a/text()").extract()
        time=paper.xpath(".//*[@class='dayTitle']/a/text()").extract()
        content=paper.xpath(".//*[@class='postCon']/div/text()").extract()
         
        item=MytestprojectItem(url=url,title=title,time=time,content=content)
        yield item
    pass

將提取出的內容封裝成Item對象,使用關鍵字yield提交。

強化爬蟲模塊-翻頁
有時候就是需要翻頁,以獲取更多數據,然後解析。

修改CnblogsSpider.py,成爲以下內容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import scrapy
from scrapy import Selector
from myTestProject.items import MytestprojectItem
class CnblogsSpider(scrapy.Spider):

name="cnblogs"
allowd_domains=["cnblogs.com"]
start_urls=["https://www.cnblogs.com/bai2018/"]
def parse(self,response):
    papers=response.xpath(".//*[@class='day']")
    for paper in papers:
        url=paper.xpath(".//*[@class='postTitle']/a/@href").extract()
        title=paper.xpath(".//*[@class='postTitle']/a/text()").extract()
        time=paper.xpath(".//*[@class='dayTitle']/a/text()").extract()
        content=paper.xpath(".//*[@class='postCon']/div/text()").extract()
         
        item=MytestprojectItem(url=url,title=title,time=time,content=content)
        yield item
    next_page=Selector(response).re(u'<a href="(\S*)">下一頁</a>')
    if next_page:
        yield scrapy.Request(url=next_page[0],callback=self.parse)
    pass

在scrapy的選擇器方面,使用xpath和css,可以直接將CnblogsSpider下的parse方法中的response參數使用,如response.xpath或response.css。

而更通用的方式是:使用Selector(response).xxx。針對re則爲Selector(response).re。

關於yield的說明:https://blog.csdn.net/mieleizhi0522/article/details/82142856

強化爬蟲模塊-存儲
當Item在Spider中被收集時候,會傳遞到Item Pipeline。

修改pipelines.py成爲以下內容:

1
2
3
4
5
6
7
8
9
10
11
12
import json
from scrapy.exceptions import DropItem
class MytestprojectPipeline(object):

def __init__(self):
    self.file=open('papers.json','wb')
def process_item(self, item, spider):
    if item['title']:
        line=json.dumps(dict(item))+"\n"
        self.file.write(line.encode())
        return item
    else:
        raise DropItem("Missing title in %s"%item)

重新實現process_item方法,收集item和該item對應的spider。然後創建papers.json,轉化item爲字典,存儲到json表中。

另外,根據提示打開pipelines.py的開關。在settings.py中,使能ITEM_PIPELINES的開關如下:

然後在cmd中執行scrapy crawl cnblogs即可

另外,還可以使用scrapy crawl cnblogs -o papers.csv進行存儲爲csv文件。

需要更改編碼,將csv文件以記事本方式重新打開,更正編碼後重新保存,查看即可。

強化爬蟲模塊-圖像下載保存
設定setting.py
1
2
3
4
5
6
7
8
9
10
11
12
ITEM_PIPELINES = {

'myTestProject.pipelines.MytestprojectPipeline':300,
'scrapy.pipelines.images.ImagesPipeline':1

}
IAMGES_STORE='.//cnblogs'
IMAGES_URLS_FIELD = 'cimage_urls'
IMAGES_RESULT_FIELD = 'cimages'
IMAGES_EXPIRES = 30
IMAGES_THUMBS = {

'small': (50, 50),
'big': (270, 270)

}
修改items.py爲:
1
2
3
4
5
6
7
8
9
10
11
12
import scrapy
class MytestprojectItem(scrapy.Item):

# define the fields for your item here like:
# name = scrapy.Field()
url=scrapy.Field()
time=scrapy.Field()
title=scrapy.Field()
content=scrapy.Field()

cimage_urls=scrapy.Field()
cimages=scrapy.Field()
pass

修改CnblogsSpider.py爲:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import scrapy
from scrapy import Selector
from myTestProject.items import MytestprojectItem
class CnblogsSpider(scrapy.Spider):

name="cnblogs"
allowd_domains=["cnblogs.com"]
start_urls=["https://www.cnblogs.com/bai2018/"]
def parse(self,response):
    papers=response.xpath(".//*[@class='day']")
    for paper in papers:
        url=paper.xpath(".//*[@class='postTitle']/a/@href").extract()[0]
        title=paper.xpath(".//*[@class='postTitle']/a/text()").extract()
        time=paper.xpath(".//*[@class='dayTitle']/a/text()").extract()
        content=paper.xpath(".//*[@class='postCon']/div/text()").extract()
         
        item=MytestprojectItem(url=url,title=title,time=time,content=content)
        request=scrapy.Request(url=url, callback=self.parse_body)
        request.meta['item']=item

        yield request
    next_page=Selector(response).re(u'<a href="(\S*)">下一頁</a>')
    if next_page:
        yield scrapy.Request(url=next_page[0],callback=self.parse)
    pass
 
def parse_body(self, response):
    item = response.meta['item']
    body = response.xpath(".//*[@class='postBody']")
    item['cimage_urls'] = body.xpath('.//img//@src').extract()
    yield item

總之,修改以上三個位置。在有時候配置正確的時候卻出現圖像等下載失敗,則可能是由於setting.py的原因,需要重新修改。

啓動爬蟲
建立main函數,傳遞初始化信息,導入指定類。如:

1
2
3
4
5
6
7
8
9
from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings

from myTestProject.spiders.CnblogSpider import CnblogsSpider

if __name__=='__main__':

process = CrawlerProcess(get_project_settings())
process.crawl('cnblogs')
process.start()

修正
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
import scrapy
from scrapy import Selector
from cnblogSpider.items import CnblogspiderItem
class CnblogsSpider(scrapy.Spider):

name="cnblogs"
allowd_domains=["cnblogs.com"]
start_urls=["https://www.cnblogs.com/bai2018/"]
def parse(self,response):
    papers=response.xpath(".//*[@class='day']")
    for paper in papers:
        urls=paper.xpath(".//*[@class='postTitle']/a/@href").extract()
        titles=paper.xpath(".//*[@class='postTitle']/a/text()").extract()
        times=paper.xpath(".//*[@class='dayTitle']/a/text()").extract()
        contents=paper.xpath(".//*[@class='postCon']/div/text()").extract()
        for i in range(len(urls)):
            url=urls[i]
            title=titles[i]
            time=times[0]
            content=contents[i]
            item=CnblogspiderItem(url=url,title=title,time=time,content=content)
            request = scrapy.Request(url=url, callback=self.parse_body)
            request.meta['item'] = item
            yield request
    next_page=Selector(response).re(u'<a href="(\S*)">下一頁</a>')
    if next_page:
        yield scrapy.Request(url=next_page[0],callback=self.parse)
    pass

def parse_body(self, response):
    item = response.meta['item']
    body = response.xpath(".//*[@class='postBody']")
    item['cimage_urls'] = body.xpath('.//img//@src').extract()
    yield item

感謝您能通過各種渠道找到我,並學習相關。
作文粗糙,有任何不明白或者因故過時,敬請留言。 感謝批評指正。
原文地址https://www.cnblogs.com/bai2018/p/11255185.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章