1. 程式人生 > >(爬蟲)採用BeautifulSoup和正則爬取今日頭條圖集.詳細!

(爬蟲)採用BeautifulSoup和正則爬取今日頭條圖集.詳細!

用beautifulsoup提取文字資訊,正則匹配關鍵的圖片資訊.

最後存入資料庫mongodb.

完成後的感想: 其實分析網頁是最關鍵的一個環節.

ajax分析,json處理等等,還是需要多點練習.

下面是程式碼:

'''
步驟:
1. 首先抓取索引頁的內容,利用requests請求目標站點,獲得索引頁html程式碼,返回結果.
2. 解析返回結果,得到詳情頁(也就是每一個圖集的url)的連結,進一步用requests請求詳情頁的資訊
3. 分析詳情頁,得到圖片的url,並把url儲存到MongoDB資料庫中
4. 多執行緒,提高抓取效率
工具庫:beautifulsoup re pymongo資料庫 requests
'''

import requests
from urllib.parse import urlencode
from requests.exceptions import RequestException
from bs4 import BeautifulSoup
from hashlib import md5
from multiprocessing import Pool

import re
import os
import json
import pymongo

# 以下是需要用到的引數, 設為全域性變數既可. 也可以另存到一個配置檔案config.py
MONGO_URL = 'localhost'
MONGO_DB = 'toutiao'
MONGO_TABLE = 'toutiao'
GROUP_START = 0
GROUP_END = 10
KEYWORD = '街拍'

# pymongo  建立mongodb的連結,用於把資料存入資料庫
mongo_client = pymongo.MongoClient(MONGO_URL)
mongo_db = mongo_client[MONGO_DB]

'''
經分析網站,每個圖集的url是通過ajax的方式加載出來,
而每個圖集頁面的圖片是存在該html頁面中的一個json串中
爬取圖片,大體分為兩個步驟:
    1. 通過設定get請求引數的方式獲取,每個圖集的url
    2. 然後再請求每個圖集的url,在每個圖集的html中,用BeautifulSoup獲取文字資訊(標題)
    再用正則表示式匹配出我們需要的json串,最後處理json串,最終就可以得到我們想要的圖片url
把圖片存入資料庫
'''

def get_index_page(offset,keyword):
    # 通過設定get請求引數的方式,獲取索引網頁資訊
    data = {
        'offset': offset,
        'format': 'json',
        'keyword': keyword,
        'autoload': 'true',
        'count': '20',
        'cur_tab': 1,
        'from': 'search_tab'
    }
    headers = {'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'}
    url = 'https://www.toutiao.com/search_content/?'+urlencode(data)
    try:
        response = requests.get(url,headers=headers)
        if response.status_code == 200:
            # 直接把返回的內容以json格式返回
            return response.json()
        return None
    except RequestException:
        print('請求索引頁失敗')
        return None

def parse_index_page(data):
    # 解析索引網頁 (該網頁返回的是json串)
    if data and 'data' in data.keys():
        for item in data.get('data'):
            # 這裡返回的是每個圖集網頁的url(在這個url中才有我們想要的圖片)
            yield item.get('article_url')

def get_detail_page(url):
    # 獲取圖集網頁的html資料,並以文字的形式返回
    # 這個headers引數 可以提取出去,當作全域性變數來使用
    headers = {'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'}
    try:
        response = requests.get(url,headers=headers)
        if response.status_code == 200:
            return response.text
        return None
    except RequestException:
        # print('請求詳情頁出錯',url)
        return None

def parse_detail_page(html,url):
    # 解析詳情頁(圖集網頁),獲得該圖集的標題和圖片url
    try:
        soup = BeautifulSoup(html,'lxml')
        title = soup.select('title')[0].get_text()
        image_pattern = re.compile('JSON.parse\("([\s\S]+?)"\),')
        images = re.search(image_pattern,html)
        if images:
            images = images.group(1)
            images = re.sub(r'\\','',images)
            data = json.loads(images)
            if data and 'sub_images' in data.keys():
                sub_images = data.get('sub_images')
                img_list = [item.get('url') for item in sub_images]
                # 下載圖片
                for img_url in img_list:
                    download_image(img_url)
                # 把獲取好的資料以字典形式返回
                return {
                    'title':title,
                    'url':url,
                    'images':img_list,
                }
    except IndexError:
        return None

def save_2_mongo(result):
    #儲存到資料庫
    if mongo_db[MONGO_TABLE].insert(result):
        print('save to mongo successfuly',result)
        return True
    return False

def download_image(url):
    # 下載圖片
    print('正在下載',url)
    headers = {'User-Agent':'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.106 Safari/537.36'}
    try:
        response = requests.get(url,headers=headers)
        if response.status_code == 200:
            # 下載圖片
            save_image(response.content)
        return None
    except RequestException:
        print('請求圖片出錯',url)
        return None

def save_image(content):
    # 下載
    # 當前路徑/KEYWORD  比如:/home/xiaohaozi/進階之路/爬蟲/今日頭條街拍/街拍  方便查詢下載好的圖片
    # 關鍵字可以改變,每改變一次關鍵字,就需要建立一個新的資料夾
    dir = os.path.dirname(os.path.realpath(__file__)) + r'/' + KEYWORD
    if not os.path.exists(dir):
        os.makedirs(dir)
    # 每個圖片用hash的方法命名,避免重複下載
    file_path = '{0}/{1}.{2}'.format(dir,md5(content).hexdigest(),'jpg')
    if not os.path.exists(file_path):
        with open(file_path,'wb') as f:
            f.write(content)

def main(offset):
    # 主函式
    index_html = get_index_page(offset,KEYWORD)
    for url in parse_index_page(index_html):
        detail_html = get_detail_page(url)
        if detail_html:
            result = parse_detail_page(detail_html,url)
            if result:
                save_2_mongo(result)
        


if __name__ == "__main__":
    # 多程序 程序池
    groups = [i*20 for i in range(GROUP_START,GROUP_END+1)]
    pool =  Pool()
    pool.map(main,groups)

爬取內容截圖:

下載的圖片

資料庫 (偷了個小懶,沒用可視工具,直接終端截的)

勤能補拙 

請努力  xiaohaozi