(3)php爬蟲---mysql大批數據導入數據庫-4種方法比較

今天心情不錯,繼續來填我的爬蟲項目的坑,在這裏我已經拿到了優酷動漫上的數據了,大約有3000條左右。正是數據量有點多,不可能人工用手填入數據庫的,不然還不累死,而且還會出錯,這樣子做不靠譜是最笨的方法。所以這裏面我第一個想到的就是直接使用sql語句插入,一條條的插入數據庫。

我的數據具體是這個樣子的:


//$v[0]===>動漫簡介
//$v[1]===>動漫圖片url
//$v[2]===>動漫名稱
//$v[3]===>動漫外鏈數組

(1)直接插入

所以具體的實現代碼如下:

//方法1:直接插入
foreach($json as $k=>$v){
    //$v[0]===>動漫簡介
    //$v[1]===>動漫圖片url
    //$v[2]===>動漫名稱
    //$v[3]===>動漫外鏈數組
    //插入數據到list表
    $sql="INSERT INTO `v_list` (`id`,`type`,`title`,`img_url`,`abstract`,`episode`)
          VALUES ($k,0,'$v[2]','$v[1]','$v[0]',".sizeof($v[3]).")";
    if($conn->query($sql)){
        echo '插入數據成功!';
    }else{
        die('插入數據失敗:'.$conn->error);
    }
    foreach($v[3] as $kk=>$vv){
        //插入數據到vediolist
        $sql="INSERT INTO `v_vediolist` (`belong`,`vedio_url`,`title`)VALUES($k,'$vv[1]','$vv[0]')";
        if($conn->query($sql)){
            echo '插入數據成功!';
        }else{
            die('插入數據失敗:'.$conn->error);
        }
    }
}

這種方法真的是慢,花了70秒左右。


3000條數據就70秒,那數據多起來不就等幾天幾夜也沒錄完。所以開始找另外一種方法。

(2)MySQLi預處理

//方法2:MySQLi 預處理
$stmt1 = $conn->prepare("INSERT INTO `v_list` (`id`,`type`,`title`,`img_url`,`abstract`,`episode`)
            VALUES (?,?,?,?,?,?)");
$stmt2 = $conn->prepare("INSERT INTO `v_vediolist` (`belong`,`vedio_url`,`title`)VALUES(?,?,?)");
foreach($json as $k=>$v){
    //$v[0]===>動漫簡介
    //$v[1]===>動漫圖片url
    //$v[2]===>動漫名稱
    //$v[3]===>動漫外鏈數組
    //插入數據到list表
    $ref1["id"] = $k;
    $ref1["type"] = 0;
    $ref1["title"] = $v[2];
    $ref1["img_url"] = $v[1];
    $ref1["abstract"] = $v[0];
    $ref1["episode"] = count($v[3]);
    $stmt1->bind_param("ddsssd",$ref1["id"],$ref1["type"],$ref1["title"],$ref1["img_url"],$ref1["abstract"],$ref1["episode"]);
    $stmt1->execute();
    foreach($v[3] as $kk=>$vv){
        //插入數據到vediolist
        $stmt2->bind_param("dss",$k,$vv[1],$vv[0]);
        $stmt2->execute();
    }
}
這種方法其實也沒有什麼優化,反而是做了安全處理,反而導致更加的慢了。

結果如下圖:




所以沒有辦法,又要找一種方法纔行。之後這次的效果非常好。

(3)逗號拼接法

//方法3:逗號隔開
//INSERT INTO table_name (列1, 列2,...) VALUES (值1, 值2,....),(值1, 值2,....),(值1, 值2,....)
$sql1="INSERT INTO `v_list` (`id`,`type`,`title`,`img_url`,`abstract`,`episode`)VALUES";
$sql2="INSERT INTO `v_vediolist` (`belong`,`vedio_url`,`title`)VALUES";
foreach($json as $k=>$v){
    //$v[0]===>動漫簡介
    //$v[1]===>動漫圖片url
    //$v[2]===>動漫名稱
    //$v[3]===>動漫外鏈數組
    //插入數據到list表
    $sql1.="($k,0,'$v[2]','$v[1]','$v[0]',".sizeof($v[3])."),";
    foreach(@$v[3] as $kk=>$vv){
        $sql2.="($k,'$vv[1]','$vv[0]'),";
    }
}
//從字符串右側移除字符
$sql1 = rtrim($sql1,',');
$sql2 = rtrim($sql2,',');
if($conn->query($sql1)){
    echo '插入數據成功!';
}else{
    die('插入數據失敗:'.$conn->error);
}
if($conn->query($sql2)){
    echo '插入數據成功!';
}else{
    die('插入數據失敗:'.$conn->error);
}

使用這個方法後,速度快到不要不要的,簡直是指數級的優化呀。

結果如下圖:


這種方法只要0.1秒左右就全部數據都導入了,速度真的是太快了。雖然好辦法已經找到了,但是做技術要不斷的探索才能不斷進步,所以我又使用了事務的方法來導入數據。

(4)事務

////方法4:事務
//關閉自動提交
$conn->autocommit(false);
foreach($json as $k=>$v){
    //$v[0]===>動漫簡介
    //$v[1]===>動漫圖片url
    //$v[2]===>動漫名稱
    //$v[3]===>動漫外鏈數組
    //插入數據到list表
    $sql1="INSERT INTO `v_list` (`id`,`type`,`title`,`img_url`,`abstract`,`episode`)
          VALUES ($k,0,'$v[2]','$v[1]','$v[0]',".sizeof($v[3]).")";
    $conn->query($sql1);

    foreach($v[3] as $kk=>$vv){
        //插入數據到vediolist
        $sql2="INSERT INTO `v_vediolist` (`belong`,`vedio_url`,`title`)VALUES($k,'$vv[1]','$vv[0]')";
        $conn->query($sql2);
    }
}
//上面的操作無錯時執行事務提交
if(!$conn->errno){
    $conn->commit();
    echo 'ok';
}else{//錯誤的話回滾
    echo 'err';
    $conn->rollback();
}
結果如下圖:




這種方法是第3種的兩倍左右,但是這個方法有個好處是可以回滾,只要有一個地方出錯了,就全部都放棄不要,回到剛開始要進行插入數據時的狀態。

總結:

這四種的方式第1,2是最慢的不可取,所以第3,4這兩種可以自己衡量一下,數據允許出點小錯誤的話,那第3是一個非常好的選擇,不然就第4種吧。

最後,我的視頻網站上的動畫欄目的數據也能運行了,效果如下:






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章