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。
這裡通過將連結進行處理,轉換成檔名,最後儲存到所屬的那個類裡;