1
shiny 286 天前
不试试 curl_multi_exec ?
|
2
a282810 286 天前
|
3
simonlu9 286 天前 1
pthread 试下
|
4
huyiwei 286 天前
多开几个进程呗
|
5
a282810 286 天前
要求 php7.1 以上的 https://github.com/Yurunsoft/YurunHttp
|
6
wonderfulcxm 286 天前 via iPhone
guzzle 就可以
|
7
abccccabc OP ```
@a282810 以前爬东西用过 https://github.com/ares333/php-curl ``` 简单看了一下使用示例,并没有看到并发的相关操作。而且此包很久都没有更新了。处于无维护状态。 |
8
panlatent 286 天前
用 curl 拓展或者 Guzzle 库,推荐后者, 尽量不要尝试多进场/线程方案,坑太多。
|
9
k9982874 286 天前 via Android
php 现在能并发了?牛!另外爬东西不试试 py ?
|
10
vacker 286 天前 via iPhone
我选择使用队列
|
11
hefish 286 天前
这思路不对啊,这不是应该往异步方面去考虑吗?怎么硬往并发上去凑?
|
12
a282810 286 天前
@abccccabc #7 其实是基于 curl_multi_exec , 能实现需要的功能就可以了,Curl::add()添加任务到任务池,Curl::start()开始执行任务并阻塞
|
13
abccccabc OP @k9982874 不是做爬虫,是复制 web 文章到我的论坛,同时要将图片进行本地化。而且还要替换掉内容中的外部图片地址。
@a282810 https://github.com/ares333/php-curl 这个项目里感觉更像异步,并发的话,肯定还要处理后续事情。他的项目示例里没有体现出来。 我是复制一些网络上优秀的文章到 dz 论坛,同时需要替换掉文章内容对应的 bbcode 图片代码。异步真不知道怎么操作,并发的话,我知道后续会有一个结果,对这个结果 foreach 就可以得到下载后图片。方便处理后续替换入库等操作。 |
14
abccccabc OP |
16
abccccabc OP @k9982874 没玩过爬虫,我是手工复制文章到论坛。有时候因为文章的图片太多,导致图片本地化失败。到目前为止,还没有自动采集过别人的文章入数据库的事情。
白嫖???工具包我只能白嫖呀,像这样的工具包 Yurunsoft/YurunHttp 我写不出来的,只能用别人写好的工具包。 |
17
UFc8704I4Bv63gy2 286 天前
帖子保存起来然后异步去下载图片,什么年代了还同步取图
并发取图 curl_multi_exec 推荐,pthread 不推荐坑多 |
18
wpjscc 286 天前 via Android
|
19
abccccabc OP 沃得天呐,你们到底知道多少这种 PHP 工具包呀?
看来是我见识少呀,向各路并发/异步 PHP 高手学习学习。展示一下你写的 并发/async php 代码???让我开开眼界呗。 |
20
erquiasz0825 285 天前
guzzle 简单好用,默认也是用 curl_multi_exec ,不是多线程也不是多进程,而是用非阻塞 I/O 的原理。
|
21
lasuar 285 天前
最近发现的一条 curl 并发命令写法(8 个并发):
seq 8 | xargs -I {} sh -c 'curl -s http://xxx:3000 %{http_code}&' |
22
lasuar 285 天前
seq 8 | xargs -I {} sh -c 'curl -s http://xxx:3000 %{http_code} &'
|
23
abccccabc OP @erquiasz0825 guzzle 简单好用,默认也是用 curl_multi_exec ,不是多线程也不是多进程,而是用非阻塞 I/O 的原理。
楼上有人建议过,我看了下,他的版本让人真的好纠结:用 v6 版本 php 版本为 >=5.5 and <8.0 ,用 v7 版本, php >= 7.2.5 。 现在在看 Yurunsoft/YurunHttp |
25
ben1024 285 天前
guzzle ,reactphp 都可以,curl_multi_exec 原生也可以
|
26
zzzyyysss 285 天前
这种就该在前端用 js 处理,你的 php 只需要一个上传的接口,前端把图拿出来 然后一个个直接传给 php ,php 返回保存在服务器的地址,然后你再前端用 js 把原来的地址替换,然后保存就 ok
|
27
liaoxx 285 天前
有幸写过一个用 yeild 和 guzzle/http 的请求池写过一个工具类
/** * 异步/并发/批量请求 (慎用) * @param string $url 请求地址 * @param array $allParams 所有请求参数 int[{once request params}] * @param array $options 请求配置 ['headers'=>[]] * @param callable|null $onSuccess 请求成功回调函数 function(ResponseInterface $response,int $index,array $params){} * @param callable|null $onFailure 请求失败回调函数 function(\Exception $exception,int $index,array $params){} * @param callable|null $onComplete 请求完成回调函数 * @return void * @author LiaoYongjian * @date 2024-01-19 17:43 */ public function postAsyncRequests(string $url, array $allParams, array $options = [], callable $onSuccess = null, callable $onFailure = null, callable $onComplete = null) { $headers = $options['headers'] ?? []; $client = $this->getCli(); //生成器 用于生成异步请求 $generator = function () use ($client, $allParams, $url, $headers, $onSuccess, $onFailure) { foreach ($allParams as $index => $params) { yield function () use ($client, $url, $headers, $index, $params, $onSuccess, $onFailure) { //异步请求 return $client->postAsync($url, [ 'headers' => $headers, 'json' => $params, ])->then( function ($response) use ($onSuccess, $index, $params) { if ($onSuccess) { $onSuccess($response, $index, $params); } return $response; }, function (\Exception $e) use ($onFailure, $index, $params) { if ($onFailure) { $onFailure($e, $index, $params); } throw $e; } ); }; } }; //异步请求池 $pool = new Pool($client, $generator()); //异步请求池的回调函数 $responses = $pool->promise()->wait(); if ($onComplete){ $onComplete($responses); } } |
28
cybort 285 天前 via Android
超时是给你限流了吧,你请求的快限的更快。
|
29
putyy 285 天前
原生 curl_multi
|
30
putyy 285 天前
如果资源存的七牛 还可以用七牛云的接口帮下载
|
31
abccccabc OP @zzzyyysss
你说的是这样的吗? ``` var allimg = 获取到的图片数组; var oldcontent = 原内容; for(var i=0; i<allimg.length; i++){ $.post('url', 参数, function(ret) { if(ret['code'] == 200) { oldcontent = oldcontent.replace(ret['oldimgurl'], ret['newimgurl']); }else{ console.log(错误信息); } }, 'json'); } ``` 这样有一个很大的问题:多个异步去修改同一全局变量,必须要锁定全局变量 oldcontent ,然后用队列的形式去替换 oldcontent 内容,不然最后只会有一个修改 oldcontent 生效。 这样更麻烦,搞不定。 ------------------- php 用了并发,现在问题也不小, ``` <?xml version="1.0" encoding="UTF-8"?> <Error> <Code>AccessDenied</Code> <Message>You are denied by bucket referer policy.</Message> <RequestId>65F44FE6D4BE2035341DF46B</RequestId> <HostId>40114.oss-cn-beijing.aliyuncs.com</HostId> <BucketName>blog-picture-240114</BucketName> <EC>0003-00000503</EC> <RecommendDoc>https://api.aliyun.com/troubleshoot?q=0003-00000503</RecommendDoc> </Error> ``` 这节奏似乎只能放弃 PHP 并发了。 |
33
zzzyyysss 285 天前
你为什么要锁定全局变量,你的目标不就是 源代码中的 图片地址远程换本地吗?
你可以在任何时间点 处理这个操作。 js 那个方法 你只要在上传完毕之后,用最新的地址 从富文本中替换旧地址就可以了。 或者你在点击保存按钮之后加个 loading 统一处理。 之所以推荐你在前端处理是因为有些网站你用后台 php 去抓图片会有防盗链的。 |
34
abccccabc OP @zzzyyysss 我试过了,多个异步去修改 oldcontent 替换旧图片地址,只有 for 循环最后 i 变量替换操作生效。 现在我明白,是要对 oldcontent 加锁,这应该就是竞争。太深澳了,又搞不定。唉。
看来现在得请教 JS 高手了。 |
35
zzzyyysss 284 天前
```
const images = []; const replaceData = {}; const asyncPost = (url, data) => { return new Promise((resolve, reject) => { $.post(url, data, (ret) => { if(ret['code'] == 200) { resolve(ret); } else { reject('获取图片出错') } }) }) } // 每当拿到新的图片时调用 const onNewImage = async (oldImgUrl) => { if (!replaceData[oldImgUrl]) { const ret = await asyncPost(url, data); replectData[ret['oldImgUrl']] = ret['newImgUrl']; } } // 在保存之前 处理 content const beforeSubmit = (content) => { Object.keys.forEach(oldUrl => { content.replaceAll(oldUrl, replaceData[newUrl]) }) return content; } ``` 大概就是这样,你可以试试 |
36
alex8 270 天前
没有稳定的原生解决方案, 上层的 composer 里更不会有。
|
37
lyxxxh2 253 天前
|