最近一段時間,今日頭條各種推送python相關的文檔,什么“python都要加入高考了,再不學就out了”等等特別火熱,正好公司領導安排我去爬取一些網站新聞信息,可以趁著這個機會學習學習python,所以就決定用python來完成本次的爬取工作。因為之前沒有接觸過python,所以直接上手遇到了各種各樣的問題,還好最后都解決了。
Scrapy簡介
Scrapy是Python開發的一個快速,高層次的屏幕抓取和Web抓取框架,用于抓取Web站點并從頁面中提取結構化的數據。
下圖展示了Scrapy的大致架構,其中包含了主要組件和系統的數據處理流程(綠色箭頭表示)。下面會對組件和流程進行了一個簡單的解釋。
組件
1.Scrapy Engine(Scrapy引擎)
Scrapy引擎是用來控制整個系統的數據處理流程,并進行事務處理的觸發。更多的詳細內容可以看下面的數據處理流程。
2.Scheduler(調度程序)
調度程序從Scrapy引擎接受請求并排序列入隊列,并在Scrapy引擎發出請求后返還給它們。
3.Downloader(下載器)
下載器的主要職責是抓取網頁并將網頁內容返還給蜘蛛(Spiders)。
4.Spiders(蜘蛛)
蜘蛛是有Scrapy用戶自己定義用來解析網頁并抓取制定URL返回的內容的類,每個蜘蛛都能處理一個域名或一組域名。換句話說就是用來定義特定網站的抓取和解析規則。
5.Item Pipeline(項目管道)
項目管道的主要責任是負責處理有蜘蛛從網頁中抽取的項目,它的主要任務是清晰、驗證和存儲數據。當頁面被蜘蛛解析后,將被發送到項目管道,并經過幾個特定的次序處理數據。每個項目管道的組件都是有一個簡單的方法組成的Python類。它們獲取了項目并執行它們的方法,同時還需要確定的是是否需要在項目管道中繼續執行下一步或是直接丟棄掉不處理。
項目管道通常執行的過程有:
清洗HTML數據 驗證解析到的數據(檢查項目是否包含必要的字段) 檢查是否是重復數據(如果重復就刪除) 將解析到的數據存儲到數據庫中
6.Middlewares(中間件)
中間件是介于Scrapy引擎和其他組件之間的一個鉤子框架,主要是為了提供一個自定義的代碼來拓展Scrapy的功能。
數據處理流程
Scrapy的整個數據處理流程有Scrapy引擎進行控制,其主要的運行方式為:
1.引擎打開一個域名,蜘蛛處理這個域名,并讓蜘蛛獲取第一個爬取的URL。
2.引擎從蜘蛛那獲取第一個需要爬取的URL,然后作為請求在調度中進行調度。
3.引擎從調度那獲取接下來進行爬取的頁面。
4.調度將下一個爬取的URL返回給引擎,引擎將它們通過下載中間件發送到下載器。
5.當網頁被下載器下載完成以后,響應內容通過下載中間件被發送到引擎。
6.引擎收到下載器的響應并將它通過蜘蛛中間件發送到蜘蛛進行處理。
7.蜘蛛處理響應并返回爬取到的項目,然后給引擎發送新的請求。
8.引擎將抓取到的項目項目管道,并向調度發送請求。
9.系統重復第二部后面的操作,直到調度中沒有請求,然后斷開引擎與域之間的聯系。
以上來自網絡,現在開始真正的開發:
新建工程:
進入想保存項目的路徑執行:
scrapy startproject <your project name>
目錄結構及其說明請自行google或baidu.
在PyCharm中導入:
Spider是整個項目中最核心的類,在這個類里我們會定義抓取對象(域名、URL)以及抓取規則。
在spiders下新建python文件:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import scrapy
from scrapy import Selector
from news_xagx.items import NewsXagxItem
class XiaoHuarSpider(scrapy.spiders.Spider):
name = "xasoftpark"
allowed_domains = ["**********.com"]
start_urls = [
"http://www.**********.com/info/iList.jsp?cat_id=10055",
"http://www.**********.com/info/iList.jsp?cat_id=10056",
"http://www.**********.com/info/iList.jsp?cat_id=10057",
"http://www.**********.com/info/iList.jsp?cat_id=10058",
]
def parse(self, response):
baseUrl = 'http://www.**********.com/'
selector = Selector(response)
links = selector.xpath('/html/body/div[8]/div[1]/ul//li/a/@href')
for link in links:
url = baseUrl + link.extract()
yield scrapy.Request(url, callback=self.parse_news_contents)
#爬取下級頁面內容
def parse_news_contents(self, response):
item = NewsXagxItem()
news_date_content = response.xpath('/html/body/div[5]/div/div[5]').xpath('string(.)').extract()[0]
item['newsDate'] = self.get_news_date(news_date_content)
item['title'] = response.xpath('/html/body/div[5]/div/div[3]').xpath('string(.)').extract()[0]
item['content'] = response.xpath('/html/body/div[5]/div/div[@class="cent_nr_box"]').xpath('string(.)').extract()[0]
yield item
#截取日期
def get_news_date(self, content):
data = u'發布時間:'
date_index = content.find(u"發布時間:") + len(u"發布時間:")
news_data = content[date_index : date_index + 10]
return news_data
MongoDB配置,在settings.py中添加MongoDB配置:
ITEM_PIPELINES = {
'news_xagx.pipelines.NewsXagxPipeline': 300,
}
MONGODB_SERVER = "localhost"
MONGODB_PORT = 27017
MONGODB_DB = "news_xa"
MONGODB_COLLECTION = "news"
pipelines.py
# -*- 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
import codecs
import json
import pymongo
from scrapy import log
from scrapy.conf import settings
class NewsXagxPipeline:
def __init__(self):
connection = pymongo.MongoClient(settings['MONGODB_SERVER'], settings['MONGODB_PORT'])
db = connection[settings['MONGODB_DB']]
self.collection = db[settings['MONGODB_COLLECTION']]
words_to_filter = ['資金', '政策', 'IT', '創新', '扶持', '項目申報']
def process_item(self, item, spider):
for word in self.words_to_filter:
if word.decode('utf8') in item['title'][0] or word.decode('utf8') in item['content']:
self.collection.insert(dict(item))
log.msg("news added to MongoDB database!",
level=log.DEBUG, spider=spider)
else:
pass
至此,我們來驗證下是否成功存入MongoDB中:
mongo命令行輸入:
db.news.findOne()
輸出:
至此完成scarpy的入庫,記錄有些簡陋,慢慢細化。