經過文章得到的贊同數爬取、過濾「掘金」中的文章(python Web)

以前初學python時寫過一個練手的Demo,程序實現了在主機上根據關鍵詞和得到贊同數爬取「掘金」中的文章:利用Python爬蟲過濾「掘金」的關鍵詞檢索結果。可是這個項目只是簡單地實現了功能,在不少方面都須要增強。現利用假期在這個程序地基礎上修改了一下,加入了Web支持,而且部署到了我私人的服務器上,你們若是有興趣能夠訪問使用:點我試用html

  • 首先看一下使用方法和結果:

搜索輸入界面
假設咱們在輸入框中分別輸入了python(關鍵字)和10(得到贊數下限)後,點擊按鈕:

搜索結果

若是想要獲取更多結果,繼續點擊 '點擊得到更多結果。。'就行了,不事後臺設置了不斷獲取數據的限制(15頁搜索結果,通常夠用了)。python

1. 項目結構

項目結構

其中'main'包中是程序文件,'static'放置靜態文件,'templates'放置html模板文件,'venv'是虛擬環境,'app.py'是主程序入口文件,'requirements.txt'記錄程序全部依賴及版本號。git

2. app.py

app.py負責構建Flask應用,且因爲程序功能比較簡單,將視圖函數也放置其中,github

app = Flask(__name__)

# set the secret key. keep this really secret:
app.secret_key = os.urandom(24)

# 帶爬取的url地址,不包含請求參數
ajax_base_url = 'https://search-merger-ms.juejin.im/v1/search'

# 根目錄,返回輸入截面
@app.route('/')
def index():
    return render_template('input.html')

# 搜索功能視圖函數
@app.route('/search')
def search():
    try:
        baseline = int(request.args.get('baseline'))    # 從請求參數中獲取文章贊同數的下限值
    except ValueError:
        raise InvalidParameter('輸入框不能爲空或者請不要在輸入框第二欄中輸入非數字字符!')
    keyword = quote(request.args.get('keyword'))  # 獲取搜索的關鍵字, urllib.parse.quote() 複雜處理url中的中文
    if keyword is None or len(keyword) == 0:
        raise InvalidParameter('輸入框不能爲空!')

    params = {}  # 對應的請求參數
    params['query'] = keyword
    params['page'] = '0'
    params['raw_result'] = 'false'
    params['src'] = 'web'

    new_url = url_manager.build_ajax_url(ajax_base_url, params)     # 構建請求地址
    craw_json = crawler.craw_one_page(crawler.parse_from_json)      # 選擇json解析器
    datas = craw_json(new_url, baseline)        # 進行下載、解析,得到結果
    if datas is None or len(datas) == 0:
        return

    return render_template('output.html', datas=datas, keyword=request.args.get('keyword'), baseline=baseline)  # keyword傳原始值,不然next_page中再進行quote則會出錯

# 請求得到更多數據
@app.route('/nextPage')
def next_page():
    keyword = quote(request.args.get('keyword'))  # 獲取搜索的關鍵字, urllib.parse.quote() 複雜處理url中的中文
    try:
        baseline = int(request.args.get('baseline'))
        req_page = int(request.args.get('req_page'))
    except ValueError:
        return redirect(url_for('index'))
    if keyword is None or len(keyword) == 0:
        return redirect(url_for('index'))
    
    params = {}  # 對應的請求參數
    params['query'] = keyword
    params['page'] = str(req_page)
    params['raw_result'] = 'false'
    params['src'] = 'web'

    new_url = url_manager.build_ajax_url(ajax_base_url, params)     # 構建請求地址
    craw_json = crawler.craw_one_page(crawler.parse_from_json)      # 選擇json解析器
    datas = craw_json(new_url, baseline)        # 進行下載、解析,得到結果
    # 將結果對象構成的列表轉完成json數組
    json_array = []
    for data in datas:
        json_array.append(data.__dict__)

    return jsonify(json_array)

# 參數錯誤界面
@app.errorhandler(InvalidParameter)
def invalid_param(error):
    return render_template('param-error.html', error_message=error.message), error.status_code

if __name__ == '__main__':
    app.debug = True
    app.run()
複製代碼

app.py中主要包含了三個視圖函數:index(), search(), next_page();search()負責搜索文章數據,next_page()負責獲取下一頁的文章數據。web

3. 下載並解析數據

咱們能夠經過兩種不一樣的URL來獲取掘金的文章信息,一種會返回html數據,一種會返回JSON數據。咱們選擇第二種方式獲取JSON數據。下面首先介紹程序的下載器: downloader.pyajax

import urllib.request

def download_json(url):
    if url is None:
        print('one invalid url is found!')
        return None
    response = urllib.request.urlopen(url)
    if response.getcode() != 200:
        print('response from %s is invalid!' % url)
        return None
    return response.read().decode('utf-8')
複製代碼

經過該方法返回的是JSON的字符串數據。接下來使用解析器來解析JSON數據: json_parser.pyjson

# 將json字符創解析爲一個對象
def json_to_object(json_content):
    if json_content is None:
        print('parse error!json is None!')
        return None
    return json.loads(str(json_content))


# 從JSON構成的對象中提取出文章的title、link、collectionCount等數據,並將其封裝成一個Bean對象,最後將這些對象添加到結果列表中
def build_bean_from_json(json_collection, baseline):
    if json_collection is None:
        raise ParseError('build bean from json error! json_collection is None!')
    list = json_collection['d'] # 文章的列表
    result_list = []    # 結果的列表
    if list is None or len(list) == 0:
        return []
    for element in list:
        starCount = element['collectionCount']  # 得到的收藏數,即得到的贊數
        if int(starCount) >= baseline:   # 若是收藏數不小於baseline,則構建結果對象並添加到結果列表中
            title = element['title']
            link = element['originalUrl']
            result = ResultBean(title, link, starCount)
            result_list.append(result)      # 添加到結果列表中
            print(title, link, starCount)
    return result_list
複製代碼

4. 爬取器

上面的下載、解析均可以看做是爬取過程當中的工具,下面咱們經過爬取模塊將下載和解析過程結合起來: crawler.pyflask

# 爬取一頁信息
def craw_one_page(func):
    def in_craw_one_page(new_url, baseline=10):    # 默認baseline=10
        print('begin to main..')

        content = downloader.download_json(new_url)  # 根據URL獲取網頁
        datas = func(content, baseline)     # 一次解析所得的結果

        print('main end..')
        return datas
    return in_craw_one_page


def parse_from_json(content, baseline):
    json_collection = json_parser.json_to_object(content)
    results = json_parser.build_bean_from_json(json_collection, baseline)
    return results


def parse_from_html(content, baseline):
    html_parser.build_soup(content)  # 使用BeautifulSoup將html網頁構建成soup樹
    results = html_parser.build_bean_from_html(baseline)
    return results
複製代碼

這裏使用閉包修飾爬取函數,使咱們能夠傳入html或JSON對應的解析器。數組

完成

相關文章
相關標籤/搜索