爬蟲學習之一個簡單的網絡爬蟲

概述

這是一個網絡爬蟲學習的技術分享,主要經過一些實際的案例對爬蟲的原理進行分析,達到對爬蟲有個基本的認識,而且可以根據本身的須要爬到想要的數據。有了數據後能夠作數據分析或者經過其餘方式從新結構化展現。html

什麼是網絡爬蟲

網絡爬蟲(又被稱爲網頁蜘蛛,網絡機器人,在FOAF社區中間,更常常的稱爲網頁追逐者),是一種按照必定的規則,自動地抓取萬維網信息的程序或者腳本。另一些不常使用的名字還有螞蟻、自動索引、模擬程序或者蠕蟲。via 百度百科網絡爬蟲
網絡蜘蛛(Web spider)也叫網絡爬蟲(Web crawler)[1],螞蟻(ant),自動檢索工具(automatic indexer),或者(在FOAF軟件概念中)網絡疾走(WEB scutter),是一種「自動化瀏覽網絡」的程序,或者說是一種網絡機器人。它們被普遍用於互聯網搜索引擎或其餘相似網站,以獲取或更新這些網站的內容和檢索方式。它們能夠自動採集全部其可以訪問到的頁面內容,以供搜索引擎作進一步處理(分檢整理下載的頁面),而使得用戶能更快的檢索到他們須要的信息。via 維基百科網絡蜘蛛python

以上是百度百科和維基百科對網絡爬蟲的定義,簡單來講爬蟲就是抓取目標網站內容的工具,通常是根據定義的行爲自動進行抓取,更智能的爬蟲會自動分析目標網站結構相似與搜索引擎的爬蟲,咱們這裏只討論基本的爬蟲原理。git

###爬蟲工做原理

網絡爬蟲框架主要由控制器解析器索引庫三大部分組成,而爬蟲工做原理主要是解析器這個環節,解析器的主要工做是下載網頁,進行頁面的處理,主要是將一些JS腳本標籤、CSS代碼內容、空格字符、HTML標籤等內容處理掉,爬蟲的基本工做是由解析器完成。因此解析器的具體流程是:github

入口訪問->下載內容->分析結構->提取內容瀏覽器

分析爬蟲目標結構

這裏咱們經過分析一個網站[落網:http://luoo.net] 對網站內容進行提取來進一步瞭解!網絡

第一步 肯定目的
抓取目標網站的某一期全部音樂多線程

第二步 分析頁面結構
訪問落網的某一期刊,經過Chrome的開發者模式查看播放列表中的歌曲,右側用紅色框線圈出來的是一些須要特別注意的語義結構,見下圖所示:
落網播放列表app

以上紅色框線圈出的地方主要有歌曲名稱,歌曲的編號等,這裏並無看到歌曲的實際文件地址,因此咱們繼續查看,點擊某一個歌曲就會當即在瀏覽器中播放,這時咱們能夠看到在Chrome的開發者模式的Network中看到實際請求的播放文件,以下圖所示:框架

播放文件請求

查看請求地址

根據以上分析咱們能夠獲得播放清單的位置和音樂文件的路徑,接下來咱們經過Python來實現這個目的。dom

實現爬蟲

Python環境安裝請自行Google

主要依賴第三方庫

Requests(http://www.python-requests.org) 用來發起請求
BeautifulSoup(bs4) 用來解析HTML結構並提取內容
faker(http://fake-factory.readthedocs.io/en/stable/)用來模擬請求UA(User-Agent)

主要思路是分紅兩部分,第一部分用來發起請求分析出播放列表而後丟到隊列中,第二部分在隊列中逐條下載文件到本地,通常分析列表速度更快,下載速度比較慢能夠藉助多線程同時進行下載。
主要代碼以下:

#-*- coding: utf-8 -*-
'''by sudo rm -rf  http://imchenkun.com'''
import os
import requests
from bs4 import BeautifulSoup
import random
from faker import Factory
import Queue
import threading

fake = Factory.create()
luoo_site = 'http://www.luoo.net/music/'
luoo_site_mp3 = 'http://luoo-mp3.kssws.ks-cdn.com/low/luoo/radio%s/%s.mp3'

proxy_ips = [    '27.15.236.236'    ] # 替換本身的代理IP
headers = {
    'Connection': 'keep-alive',
    'User-Agent': fake.user_agent()
    }

def random_proxies():
    ip_index = random.randint(0, len(proxy_ips)-1)
    res = { 'http': proxy_ips[ip_index] }
    return res

def fix_characters(s):
    for c in ['<', '>', ':', '"', '/', '\\\\', '|', '?', '*']:
        s = s.replace(c, '')
    return s


class LuooSpider(threading.Thread):
    def __init__(self, url, vols, queue=None):
        threading.Thread.__init__(self)
        print '[luoo spider]'
        print '=' * 20
        self.url = url
        self.queue = queue
        self.vol = '1'
        self.vols = vols

    def run(self):
        for vol in self.vols:
            self.spider(vol)
        print '\\ncrawl end\\n\\n'
        def spider(self, vol):
        url = luoo_site + vol
        print 'crawling: ' + url + '\\n'
        res = requests.get(url, proxies=random_proxies())
                soup = BeautifulSoup(res.content, 'html.parser')
        title = soup.find('span', attrs={'class': 'vol-title'}).text
        cover = soup.find('img', attrs={'class': 'vol-cover'})['src']
        desc = soup.find('div', attrs={'class': 'vol-desc'})
        track_names = soup.find_all('a', attrs={'class': 'trackname'})
        track_count = len(track_names)
        tracks = []
        for track in track_names:
            _id = str(int(track.text[:2])) if (int(vol) < 12) else track.text[:2]  # 12期前的音樂編號1~9是1位(如:1~9),以後的都是2位 1~9會在左邊墊0(如:01~09)
            _name = fix_characters(track.text[4:])
            tracks.append({'id': _id, 'name': _name})
            phases = {
                'phase': vol,                         # 期刊編號
                'title': title,                       # 期刊標題
                 'cover': cover,                      # 期刊封面
                 'desc': desc,                        # 期刊描述
                 'track_count': track_count,          # 節目數
                 'tracks': tracks                     # 節目清單(節目編號,節目名稱)
            }
            self.queue.put(phases)


class LuooDownloader(threading.Thread):
    def __init__(self, url, dist, queue=None):
        threading.Thread.__init__(self)
        self.url = url
        self.queue = queue
        self.dist = dist
        self.__counter = 0       

     def run(self):
        while True:
            if self.queue.qsize() <= 0:
                pass
            else:
                phases = self.queue.get()
                self.download(phases)

    def download(self, phases):
        for track in phases['tracks']:
            file_url = self.url % (phases['phase'], track['id'])

            local_file_dict = '%s/%s' % (self.dist, phases['phase'])
            if not os.path.exists(local_file_dict):
                os.makedirs(local_file_dict)              

            local_file = '%s/%s.%s.mp3' % (local_file_dict, track['id'], track['name'])
            if not os.path.isfile(local_file):
                print 'downloading: ' + track['name']
                res = requests.get(file_url, proxies=random_proxies(), headers=headers)
                with open(local_file, 'wb') as f:
                    f.write(res.content)
                    f.close()
                print 'done.\\n'
            else:
                print 'break: ' + track['name']


if __name__ == '__main__':
    spider_queue = Queue.Queue()

    luoo = LuooSpider(luoo_site, vols=['680', '721', '725', '720'],queue=spider_queue)
    luoo.setDaemon(True)
    luoo.start()

    downloader_count = 5
    for i in range(downloader_count):
        luoo_download = LuooDownloader(luoo_site_mp3, 'D:/luoo', queue=spider_queue)
        luoo_download.setDaemon(True)
        luoo_download.start()

以上代碼執行後結果以下圖所示
執行效果
執行結果
Github地址:https://github.com/imchenkun/ick-spider/blob/master/luoospider.py

總結

經過本文咱們基本瞭解了網絡爬蟲的知識,對網絡爬蟲工做原理認識的同時咱們實現了一個真實的案例場景,這裏主要是使用一些基礎的第三方Python庫來幫助咱們實現爬蟲,基本上演示了網絡爬蟲框架中基本的核心概念。一般工做中咱們會使用一些比較優秀的爬蟲框架來快速的實現需求,好比 scrapy框架,接下來我會經過使用Scrapy這類爬蟲框架來實現一個新的爬蟲來加深對網絡爬蟲的理解!

特別申明:本文所提到的落網是我本人特別喜歡的一個音樂網站,本文只是拿來進行爬蟲的技術交流學習,讀者涉及到的全部侵權問題都與本人無關

本文首發在sudo rm -rf 採用署名(BY)-非商業性使用(NC)-禁止演繹(ND) 轉載請註明原做者

--EOF--

相關文章
相關標籤/搜索