- _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' ]; }