1. 程式人生 > >Scrapy教程——搭建環境、建立專案、爬取內容、儲存檔案(txt)

Scrapy教程——搭建環境、建立專案、爬取內容、儲存檔案(txt)

寫在前面的話

        對於一個python新手,要使用scrapy進行爬蟲,簡直是抓狂,不過一點一點的啃下來,慢慢的發現也挺有意思的,通過好幾天的白天去公司實習,晚上熬夜到凌晨寫爬蟲,現在將自己的第一次爬蟲經歷記錄下來,以備以後再學習,同時也希望可以幫助到廣大熱愛爬蟲、熱愛大資料的人;

         就像很多博主一樣,這裡先大概講解一下scrapy的入門教程。這裡提供一個scrapy的官方中文參考文件:http://scrapy-chs.readthedocs.org/zh_CN/latest/intro/tutorial.html

      接下來,我需要寫的內容包括以下幾個部分(程式設計師都知道,一切從0開始):

0、安裝scrapy

1、建立一個scrapy專案

2、定義你需要儲存的Item

3、編寫爬取網站的spider

0、安裝scrapy

          這裡說的安裝,主要是指windows,因為博主的電腦是windows10;

2、安裝python2.7,然後修改環境變數,博主這裡python安裝在C:\Python27,所以需要在path裡增加C:\Python27\;C:\Python27\Scripts\;

3、檢視版本:python --version

4、安裝pywin32,可以從官網下載。

5、安裝pywin32之後,然後開啟命令列,確認pip是否被正確安裝,輸入pip --version,其實python2.7.9之後,預設是安裝了pip;如果沒有安裝pip,可以百度。博主是使用2.7.10,所以預設安裝pip,你可以選擇更新pip版本。

6、安裝了pip,使用pip安裝scrapy,輸入命令:pip install Scrapy。安裝了Scrapy,然後就可以開始新建Scrapy專案了。

1、建立專案

        在開始爬取之前,您必須建立一個新的Scrapy專案。進入您打算儲存程式碼的目錄中,執行新建命令。

例如,我需要在D:\00Coding\Python\scrapy目錄下存放該專案,開啟命令視窗,進入該目錄,執行以下命令:

scrapy startproject  tutorial

PS:tutorial可以替換成任何你喜歡的名稱,最好是英文

      該命令將會建立包含下列內容的 tutorial 目錄:

tutorial/
    scrapy.cfg
    tutorial/
        __init__.py
        items.py
        pipelines.py
        settings.py
        spiders/
            __init__.py
            ...

這些檔案分別是:

scrapy.cfg: 專案的配置檔案
tutorial/: 該專案的python模組。之後您將在此加入程式碼。
tutorial/items.py: 專案中的item檔案.
tutorial/pipelines.py: 專案中的pipelines檔案.
tutorial/settings.py: 專案的設定檔案.
tutorial/spiders/: 放置spider程式碼的目錄.

2、定義Item

        Item 是儲存爬取到的資料的容器;其使用方法和python字典類似,並且提供了額外保護機制來避免拼寫錯誤導致的未定義欄位錯誤。我們需要從想要爬取的網站(這裡爬取新浪新聞)中獲取以下屬性:

新聞大類url、新聞大類title;

新聞小類url、新聞小類title;

新聞url、新聞title;

新聞標題、新聞內容;

       對此,在item中定義相應的欄位。編輯tutorial目錄中的 items.py 檔案:

from scrapy.item import Item, Field
class TutorialItem(Item):
    # define the fields for your item here like:
    # name = scrapy.Field()
   parent_title = Field()
   parent_url = Field()

   second_title = Field()
   second_url = Field()
   path = Field()

   link_title = Field()
   link_url = Field()
   head= Field()
   content = Field()
   pass

3、編寫爬蟲(Spider)

       Spider是使用者編寫用於從單個網站(或者一些網站)爬取資料的類。

       1、sinaSpider.py檔案:

       包含了一個用於下載的初始URL,如何跟進網頁中的連結以及如何分析頁面中的內容,提取生成 item 的方法。為了建立一個Spider,您必須繼承類,且定義以下三個屬性:

name:用於區別Spider。該名字必須是唯一的,您不可以為不同的Spider設定相同的名字。

包含了Spider在啟動時進行爬取的url列表。因此,第一個被獲取到的頁面將是其中之一。後續的URL則從初始的URL獲取到的資料中提取。

spider的一個方法。被呼叫時,每個初始URL完成下載後生成的物件將會作為唯一的引數傳遞給該函式。該方法負責解析返回的資料(response data),提取資料(生成item)以及生成需要進一步處理的URL物件。

當我們爬取了大類,然後這時候沒有儲存item,而是傳遞item到小類,爬取完小類之後,我們需要去新聞詳情頁爬取新聞的內容和標題:

主要思路是:paser->second_paser->detail_parse


以下是sinaSpider的全部程式碼:

# -*-coding: utf-8 -*-
__author__= 'George'
import sys, os
reload(sys)
sys.setdefaultencoding("utf-8")
from scrapy.spider import Spider
from scrapy.http import Request
from scrapy.selector import Selector
from tutorial.items import TutorialItem
base ="d:/dataset/" #存放檔案分類的目錄
class SinaSpider(Spider):
   name= "sina"
   allowed_domains= ["sina.com.cn"]
   start_urls= [
       "http://news.sina.com.cn/guide/"
   ]#起始urls列表

   def parse(self, response):
       items= []
       sel= Selector(response)
       big_urls=sel.xpath('//div[@id=\"tab01\"]/div/h3/a/@href').extract()#大類的url
       big_titles=sel.xpath("//div[@id=\"tab01\"]/div/h3/a/text()").extract()
       second_urls =sel.xpath('//div[@id=\"tab01\"]/div/ul/li/a/@href').extract()#小類的url
       second_titles=sel.xpath('//div[@id=\"tab01\"]/div/ul/li/a/text()').extract()

       for i in range(1,len(big_titles)-1):#這裡不想要第一大類,big_title減去1是因為最後一個大類,沒有跳轉按鈕,也去除
           file_name = base + big_titles[i]
           #建立目錄
           if(not os.path.exists(file_name)):
               os.makedirs(file_name)
           for j in range(19,len(second_urls)):
               item = TutorialItem()
               item['parent_title'] =big_titles[i]
               item['parent_url'] =big_urls[i]
               if_belong =second_urls[j].startswith( item['parent_url'])
               if(if_belong):
                   second_file_name =file_name + '/'+ second_titles[j]
                   if(not os.path.exists(second_file_name)):
                       os.makedirs(second_file_name)
                   item['second_url'] = second_urls[j]
                   item['second_title'] =second_titles[j]
                   item['path'] =second_file_name
                   items.append(item)
       for item in items:
           yield Request(url=item['second_url'],meta={'item_1': item},callback=self.second_parse)

   #對於返回的小類的url,再進行遞迴請求
   def second_parse(self, response):
       sel= Selector(response)
       item_1= response.meta['item_1']
       items= []
       bigUrls= sel.xpath('//a/@href').extract()

       for i in range(0, len(bigUrls)):
           if_belong =bigUrls[i].endswith('.shtml') and bigUrls[i].startswith(item_1['parent_url'])
           if(if_belong):
               item = TutorialItem()
               item['parent_title'] =item_1['parent_title']
               item['parent_url'] =item_1['parent_url']
               item['second_url'] =item_1['second_url']
               item['second_title'] =item_1['second_title']
               item['path'] = item_1['path']
               item['link_url'] = bigUrls[i]
               items.append(item)
       for item in items:
               yield Request(url=item['link_url'], meta={'item_2':item},callback=self.detail_parse)

   def detail_parse(self, response):
       sel= Selector(response)
       item= response.meta['item_2']
       content= ""
       head=sel.xpath('//h1[@id=\"artibodyTitle\"]/text()').extract()
       content_list=sel.xpath('//div[@id=\"artibody\"]/p/text()').extract()
       for content_one in content_list:
           content += content_one
       item['head']= head
       item['content']= content
       yield item

         2、pipelines.py

主要是對於抓取資料的儲存(txt),這裡把檔名命名為連結中'/'替換成'_'

# -*- coding: utf-8 -*-

# Define your item pipelines here
#
# Don't forget to add your pipeline to the ITEM_PIPELINES setting
# See: http://doc.scrapy.org/en/latest/topics/item-pipeline.html
from scrapy import signals
import json
import codecs
import sys
reload(sys)
sys.setdefaultencoding( "utf-8" )
class SinaPipeline(object):
    def process_item(self, item, spider):
        link_url = item['link_url']
        file_name = link_url[7:-6].replace('/','_')
        file_name += ".txt"
        fp = open(item['path']+'/'+file_name, 'w')
        fp.write(item['content'])
        fp.close()
        return item
3、setting.py

這是設定檔案,這裡需要設定同時開啟的執行緒數目、日誌列印的級別等

# -*- coding: utf-8 -*-
BOT_NAME = 'tutorial'

SPIDER_MODULES = ['tutorial.spiders']
NEWSPIDER_MODULE = 'tutorial.spiders'
ITEM_PIPELINES = {
    'tutorial.pipelines.SinaPipeline': 300,
}
LOG_LEVEL = 'INFO'
ROBOTSTXT_OBEY = True

爬取結果

這裡的資料夾是根據分類,然後建立的;

        這是大類的資料夾,現在我們已經將item都爬下來了,就需要存了,這裡只想要存內容,所以直接將item裡面的content欄位的內容寫入txt。

        這裡通過將連結進行處理,轉換成檔名,最後儲存到所屬的那個類裡;