1. 程式人生 > >scrapy爬蟲爬取動態網站

scrapy爬蟲爬取動態網站

爬取360圖片上的美女圖片

360圖片網站上的圖片是動態載入的,動態載入 就是通過ajax請求介面拿到資料喧染在網頁上。我們就可以通過遊覽器的開發者工具分析,在我們向下拉動視窗時就會出現這麼個請求,如圖所示:
這裡寫圖片描述

所以就判定這個url就是ajax請求的介面:,http://image.so.com/zj?ch=beauty&sn=30&listtype=new&temp=1,通過分析,sn=30 表示取的是前面30條資料,sn=60取的是30到60條的資料,我們就可以通過改變sn的數來拿到不同的資料,下面就開始我們的scrap專案:

# 在虛擬環境裡建立專案
scrapy startproject  image360
# 建立蜘蛛
scrapy genspider image image.so.com

專案目錄結構如下:
這裡寫圖片描述

首先建立儲存資料的模型:在items.py檔案中

import scrapy


class ImageItem(scrapy.Item):
    # define the fields for your item here like:
    title = scrapy.Field() # 圖片的標題
    tag = scrapy.Field() # 圖片的標籤
    width = scrapy.Field() # 圖片的寬度
    height = scrapy.Field
() # 圖片的高度 url = scrapy.Field() # 圖片的url

開始寫蜘蛛:在iamge.py檔案中

import scrapy
from urllib.parse import urlencode
from json import loads

class ImageSpider(scrapy.Spider):
    name = 'image' # 蜘蛛的名字
    allowed_domains = ['image.so.com'] # 允許訪問的域名

    # 因為不和以前一樣給一個初始url,所以需要重寫父類的start_requests方法
def strat_requests(self): # 定義一個基礎的url base_url = 'http://image.so.com/zj?' # 把固定的引數儲存在一個字典裡 param = {'ch': 'beauty', 'listtype': 'new', 'temp': 1} # 我們拿資料只需要改變sn的值,所以我們來個迴圈,我們拿300條資料 for page in range(10): # 把sn和對應的數新增到字典裡 param['sn'] = page * 30 # 一個完整的url full_url = base_url + urlencode(param) # 返回一個生成器, yield scrapy.Request(url=full_url, callback=self.parse) def def parse(self, response): # 把從接口裡拿到的資料轉成字典 model_dict = loads(response.text) # 找到對應的資料放在item裡 for elem in model_dict['list']: item = ImageItem() item['title'] = elem['group_title'] item['tag'] = elem['tag'] item['width'] = elem['cover_width'] item['height'] = elem['cover_height'] item['url'] = elem['qhimg_url'] yield item

資料的持久化:在pipelines.py檔案中

from scrapy import Request
from scrapy.exceptions import DropItem
from scrapy.pipelines.images import ImagesPipeline
from pymongo import MongoClient


# 下載圖片的類,繼承了scrap的ImagesPipeline類,並且重寫了裡面3個方法
class SaveImagePipeline(ImagesPipeline):

    def get_media_requests(self, item, info):
        yield Request(url=item['url'])

    def item_completed(self, results, item, info):
        if not results[0][0]:
            raise DropItem('下載失敗')
        return item

    # 獲取檔案的檔名的方法
    def file_path(self, request, response=None, info=None):
        return request.url.split('/')[-1]


# 儲存到資料庫的類
class SaveToMongoPipeline(object):

    def __init__(self, mongo_url, db_name):
        self.mongo_url = mongo_url
        self.db_name = db_name
        self.client = None
        self.db = None
        self.collect = None

    # 把item資料存入mongo資料庫裡
    def process_item(self, item, spider):
        # item['image_name'] = item['url'].split('/')[-1]
        # self.db.image.insert(dict(item))

        self.collect.insert_one(dict(item))
        return item

    # 建立連線mongo資料庫的方法,在開始爬蟲程式時自動呼叫
    def open_spider(self, spider):
        self.client = MongoClient(self.mongo_url)
        self.db = self.client[self.db_name]
        self.collect = self.db.image

    # 關閉連線的方法,在爬蟲程式結束時自動呼叫
    def close_spider(self, spider):
        self.client.close()

    # 這是個類方法
    @classmethod
    def from_crawler(cls, crawler):
        # 當return cls時就會呼叫該類的初始方法__init__,就把連線mango資料庫的引數和資料庫名字傳過去
        # crawler.setting.get('MONGO_URL')就是拿到settings.py檔案裡設定的 MONGO_URL
        return cls(crawler.settings.get('MONGO_URL'),
                   crawler.settings.get('MONGO_DB'))

在配置檔案中開啟pipelines

這裡寫圖片描述

使用webdriver

from selenium import webdriver
from bs4 import BeautifulSoup
import requests

def main():
    driver = webdriver.Chrome()
    driver.get('https://v.taobao.com/v/content/live?catetype=704&from=taonvlang')
    soup = BeautifulSoup(driver.page_source, 'lxml')
    for img_tag in soup.body.select('img[src]'):
        url = img_tag.attrs['src']
        try:
            if not str(url).startswith('http'):
                url = 'http:' + url
                filename = url[url.rfind('/') + 1:]
                resp = requests.get(url)
                with open('../images/' + filename,'wb') as f:
                    f.write(resp.content)
        except OSError:
            print(filename + '下載失敗')
    print('圖片下載完成')


if __name__ == '__main__':
    main()