(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种吧。

最后,我的视频网站上的动画栏目的数据也能运行了,效果如下:






  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 15
    评论
您好,关于将Scrapy-Redis分布式爬虫爬取的数据写入MySQL数据库,您可以按照以下步骤操作: 1. 在pip中安装PyMySQL:pip install pymysql 2. 在Scrapy项目的settings.py文件中添加数据库配置信息: ``` MYSQL_HOST = 'localhost' # 你的mysql地址 MYSQL_DBNAME = 'test' # 数据库名字,请修改 MYSQL_USER = 'root' # 数据库账号,请修改 MYSQL_PASSWORD = '123456' # 数据库密码,请修改 MYSQL_PORT = 3306 # 数据库端口号 ``` 3. 在items.py文件中定义需要存储的字段,例如: ``` import scrapy class NewsItem(scrapy.Item): title = scrapy.Field() url = scrapy.Field() date = scrapy.Field() ``` 4. 在pipelines.py文件中编写MySQL存储Pipeline: ``` import pymysql class MySQLPipeline(object): def __init__(self, mysql_host, mysql_port, mysql_user, mysql_password, mysql_dbname): self.host = mysql_host self.port = mysql_port self.user = mysql_user self.password = mysql_password self.dbname = mysql_dbname @classmethod def from_crawler(cls, crawler): return cls( mysql_host=crawler.settings.get('MYSQL_HOST'), mysql_port=crawler.settings.get('MYSQL_PORT'), mysql_user=crawler.settings.get('MYSQL_USER'), mysql_password=crawler.settings.get('MYSQL_PASSWORD'), mysql_dbname=crawler.settings.get('MYSQL_DBNAME') ) def open_spider(self, spider): self.db = pymysql.connect( host=self.host, port=self.port, user=self.user, password=self.password, db=self.dbname ) self.cursor = self.db.cursor() def close_spider(self, spider): self.db.close() def process_item(self, item, spider): data = dict(item) keys = ', '.join(data.keys()) values = ', '.join(['%s'] * len(data)) table = 'news' # 数据库表名,请修改 sql = f'INSERT INTO {table} ({keys}) VALUES ({values})' self.cursor.execute(sql, tuple(data.values())) self.db.commit() return item ``` 4. 在settings.py文件中启用Pipeline: ``` ITEM_PIPELINES = { 'myproject.pipelines.MySQLPipeline': 300 } ``` 这样,当Scrapy爬取到数据时,就会通过MySQLPipeline将数据写入MySQL数据库中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值