- _nosay
laravel中队列的使用(二)
2017-08-15 16:37:38
上一文我们已经实现了队列,任务的基本模型,现在我们来实现具体的需求。也就是说从我们五个测试url中,放入队列中,然后提取相应的title标签。
我们在前面已经在任务中拿到了url,下面开始
在控制器中执行
php artisan make:model Title -m
生成title模型,以及相应的数据库结构文件,迁移文件中内容为
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateTitlesTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('titles', function (Blueprint $table) {
$table->increments('id');
$table->string('title')->comment('采集到的标题');
$table->string('url')->comment('目标网址');
$table->integer('status')->comment('是否采集成功,0为失败,1为成功');
$table->string('message')->comment('采集返回信息');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('titles');
}
}相应model中内容为:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Title extends Model
{
protected $fillable = [
'title','url','status','message'
];
//
}执行数据库迁移命令:
php artisan migrate
在getTitlesByUrlListener.php监听器中,写入采集title标签逻辑事件,因为采集这一块,用python做起来比较便利,所以我们决定使用python来配合php进行工作,我们在app文件夹下建立Extensions\python\getTitleByUrl.py文件,具体内容为
#encoding=utf-8
from __future__ import unicode_literals
from bs4 import BeautifulSoup
import sys
import json
import urllib2
if(len(sys.argv) == 1):
print 'Error'
else:
data = {}
url = sys.argv[1]
user_agent = 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:54.0) Gecko/20100101 Firefox/54.0'
headers = { 'User-Agent' : user_agent }
req = urllib2.Request(url,None,headers)
try:
response = urllib2.urlopen(req)
except urllib2.URLError, e:
if hasattr(e, "reason"):
reason = str(e.reason)
data['status'] = 0
data['msg'] = reason
print json.dumps(data)
else:
try:
soup = BeautifulSoup(response.read(),'lxml')
data['status'] = 1
data['msg'] = soup.title.string
print json.dumps(data)
except AttributeError as e:
data['status'] = 0
data['msg'] = '此网站没有设置title标签,奇葩'
print json.dumps(data)其中使用到了python中的两个包,如果没有的话,可以通过
sudo pip install beautifulsoup4 sudo pip install lxml
进行安装。下面我们在php中,只需要调用此脚本,并且把url传过去即可。getTitlesByUrlListener.php文件相应内容
<?php
namespace App\Listeners;
use App\Events\getTitlesByUrlEvent;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Support\Facades\Log;
class getTitlesByUrlListener implements ShouldQueue
{
/**
* Create the event listener.
*
* @return void
*/
public function __construct()
{
//
}
/**
* Handle the event.
*
* @param getTitlesByUrlEvent $event
* @return void
*/
public function handle(getTitlesByUrlEvent $event)
{
//
$result = shell_exec("python ".__DIR__."/../Extensions/python/getTitleByUrl.py '".$event->url."'");
Log::info($result);
}
}这时我们尝试刷新一下网址,发现浏览器瞬间就完成了响应,同时数据库里jobs表中多了五条记录,我们在控制台执行
php artisan queue:work --daemon
然后五条命令一条一条的全部执行成功,同时日志文件中得到了相应的json文件,这时可能有人跳出来问了,你一开始的需求不是1万条吗,现在你拿5条过来测试,坑爹呢这是,好吧,现在我们把数据换成1万条试试,控制器文件修改为:
<?php
namespace App\Http\Controllers;
use App\Events\getTitlesByUrlEvent;
use Illuminate\Http\Request;
class StartController extends Controller
{
//
public function index()
{
$weburls = [
'http://www.baidu.com/',
'http://www.taobao.com/',
'http://www.qq.com/',
'http://www.youku.com/',
'http://www.muzilong.cn/',
];
for($i=0;$i<2000;$i++)
{
foreach($weburls as $key => $value)
{
event(new getTitlesByUrlEvent($value));
}
}
return "ok";
}
}这下有了1万条记录了,但是从代码上来看,唉呀,实例化1万次 getTitlesByUrlEvent这个类,代码肯定是有点问题,先执行一下,虽然最终生成了1万条记录,但是真的是好慢啊,大概20秒左右浏览器才转完吧,这肯定不行,我们需求是秒响应完成才对。还得修改代码。
这时我们需要换个思路,假如说一个用户上传上1万条记录,这样我们首先应该根据这个用户的id,把这1万条记录先入库,然后根据此用户的id生成一条任务即可,这样响应时间预想应该会得到不少的提升,说干就干,我们先在控制台执行
php artisan make:model url -m
生成相应的model以及迁移文件,名字起的很随意,凑合看啦。
相应迁移文件内容为
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUrlsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('urls', function (Blueprint $table) {
$table->increments('id');
$table->unsignedInteger('uid')->comment('用户uid');
$table->string('url')->comment('相应链接');
$table->integer('status')->default(0)->comment('采集状态');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('urls');
}
}相应Model文件内容为:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Url extends Model
{
//
protected $fillable = [
'uid','url','status'
];
}