【问题标题】:Autofill the title of website via link in a form通过表单中的链接自动填充网站标题
【发布时间】:2021-09-16 05:27:03
【问题描述】:
<form method="POST" action="{{ route('storeCompany') }}">
            @csrf
            <label>{{ __('Website URL') }}</label>
            <input type="text" name="url" value="{{ old('url') }}" placeholder="{{ __('http://example.com') }}" class="form-control" required="required">
            <label>{{ __('Website Title') }}</label>
            <input type="text" name="name" value="{{ old('name') }}" placeholder="{{ __('Example Ltd') }}" class="form-control" required="required">
            <input type="submit" name="sbNewReviewItem" class="btn btn-block btn-primary" value="{{ __('Submit New Company') }}">
</form>

我希望在用户键入“网站 URL”时自动填充“网站标题”字段,如果用户愿意,“网站标题”必须是可编辑的。我怎样才能做到这一点?请帮忙:(

示例:当用户在“网站 URL”字段中输入https://stackoverflow.com/ URL 时,“网站标题”字段必须自动填写为Stack Overflow - Where Developers Learn, Share, &amp;amp; Build Careers

【问题讨论】:

  • 假设您正在谈论查看网站主页时出现在浏览器栏中的标题,您必须向 URL 发出 http 请求,解析返回的 html 并提取title 元素的内容来自它。用户打字时可能不太实用。除非您在自己的数据库中有预定义的 URL 和标题列表? (但如果你这样做了,你将使用下拉列表或自动完成控件而不是纯文本框)
  • 请解释您所说的“网站标题”和“网站 URL”是什么意思。它是模型属性吗?
  • 正如 ADyson 所暗示的,这可能是一项相当复杂的任务。您需要考虑什么会触发“获取”。每次按键都会亮吗?您是否会首先通过一些正则表达式运行 URL 以验证用户没有输入垃圾。获得 HTML 有效负载后,您需要对其进行解析以提取 标记。这可能是也可能不是微不足道的任务。您能告诉我们到目前为止您已经尝试过什么,或者您设想它是如何工作的吗?
  • stackoverflow.com/questions/7901760/… 包含一些关于如何操作的建议

标签: php html function url page-title


【解决方案1】:

您在url-field 元素上有一个change 事件,该事件向api 网站发出获取请求,返回该网站的html 内容,然后它使用正则表达式提取html 标题,然后将其添加到名称字段。

此外,在执行获取时,我们会显示 Fetching 文本,让用户知道发生了什么。并且表单提交事件已通过preventDefault() 函数停止。用户提交表单后,您可以在此处为所欲为。

不要使用https://api.codetabs.com/v1/proxy/?quest= 来限制您的请求并向您显示Too many requests 错误,您应该使用自己的代码来获取网站内容然后返回响应。为了优化这一点,您可以只返回网站标题,以节省带宽和 CPU 周期。

您需要 api 来获取网站内容的原因是 CORS。您不能只使用从您想要的任何网站获取资源。您只能从当前网站或允许您这样做的网站执行此操作。

document.addEventListener('submit', event => {
  event.preventDefault()
})

document.addEventListener('change', async (event) => {
  if (event.target.classList.contains('url-field')) {
    await changeUrl(event.target.closest('form').elements)
  }
})

async function changeUrl (fields) {
  try {
    if (!fields.url.value) return
    fields.output.removeAttribute('hidden')
    const response = await fetch('https://api.codetabs.com/v1/proxy/?quest=' + encodeURI(fields.url.value))
    const html = await response.text()
    const match = /<title[\s\S]*?>([\s\S]*?)<\/title>/gi.exec(html)
    if (!match || !match[1]) throw new Error('No title found')
    fields.name.value = match[1].trim()
    fields.output.setAttribute('hidden', '')
  } catch (error) {
    console.error(error)
  }
}
<form method="POST" action="">
<p>
  <label>Website URL</label>
  <input type="url" name="url" value="" placeholder="http://example.com" class="form-control url-field" required>
  <output name="output" hidden>Fetching</output>
</p>
<p>
  <label>Website Title</label>
  <input type="text" name="name" value="" placeholder="Example Ltd" class="form-control">
</p>
<input type="submit" name="sbNewReviewItem" class="btn btn-block btn-primary" value="Submit New Company">
</form>

【讨论】:

  • 看起来不错,有两点说明:1. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… 确保代理 API 请求始终有效 2. 因为它在浏览器中,我认为它比正则表达式解析 HTML 有更好的方法,例如DOMDocument 和 getTagByName ;)
  • 1) 我在 url 参数中添加了encodeURI,谢谢。 2)您不想使用 DOMDocument 来解析文档,因为网站可能非常大,并且您正在将资源用于不需要的东西。您只需要从该文本中提取标题标签,而不是对其进行解析并获取各种数据。与 dom 解析相比,这种情况下的正则表达式非常快。
  • 这听起来很有见地。但我仍然可以想象 HTML 的浏览器解析器比正则表达式更有效(就像理论上一样),我不知道,但如果使用部分内容(例如前 4096 个字节左右),它可以进一步优化它(正则表达式方法相同)。也许那是一个甜蜜的地方。总而言之:这只是评论,没有要求编辑答案,更多仅供参考(今天不能再投票了,抱歉)。
  • 如果要提取所有内容,浏览器 dom 比正则表达式更有效。但是,如果您只需要一件事,那么正则表达式会胜出。
  • 不太确定。如果您需要从字符串的开头使用正则表达式解析 HTML,我不确定它是否更快。例如,这里的正则表达式不处理开头标题标签中的空格(也不是属性)。肯定会赢(也许字符串搜索更快,看到模式,对于结束标签搜索也是完全可行的)。
【解决方案2】:

因为您的示例看起来像 Laravel。 我发现用 PHP 写一个答案是合适的。

example.blade.php

<title>{{ $title ?? 'Default title' }}</title>
<form method="POST" action="{{ route('storeCompany') }}">
    @csrf
    <label>{{ __('Website URL') }}</label>
    <input type="text" name="url" value="{{ $url ?? old('url') }}" placeholder="{{ __('http://example.com') }}" class="form-control" required="required">
    <label>{{ __('Website Title') }} <small>(Leave blank to retrieve from URL)</small></label>
    <input type="text" name="name" value="{{ $title ?? old('name') }}" placeholder="{{ __('Example Ltd') }}" class="form-control">
    <input type="submit" name="sbNewReviewItem" class="btn btn-block btn-primary" value="{{ __('Submit New Company') }}">
</form>

CompanyController.php

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;

class CompanyController extends Controller
{
    public function index(){
        
        return view('example');
    }
    
    public function storeCompany(Request $request){
        
        $title = $request->name;

        if (empty($title) && filter_var($request->url, FILTER_VALIDATE_URL)){
            $response = HTTP::get($request->url);
            if ($response->ok()){
                preg_match('/<title>(.*)<\/title>/i', $response->body(), $matches);
                $title = $matches[1] ?? null;
            }
        }

        $data = [
            'url' => $request->url,
            'title' => $title
        ];
        
        return view('example', $data);
    }
}

【讨论】:

    【解决方案3】:

    用户输入数据后。

    使用$("#text_field").val();获取值

    进行ajax调用并使用以下函数获取值,将url传递给t

    require 'simple_html_dom.php';
    function dataParser($url){
        $html = new simple_html_dom();
        $html->load_file($url); 
        $title = $html->find('title',0)->innertext;
        return $title;
    }
    // something like $_GET['user_url'];
    echo  $title = dataParser('https://stackoverflow.com');
    

    此代码将输出标题,将其设置为要显示标题的 div,如下所示

    var ajaxCallResponse = ""//store the response here
    $("#title_div").val(ajaxCallResponse);
    

    【讨论】:

      【解决方案4】:

      方法如下:

      1. 阅读网站网址。
      2. 向 codetabs api 发送 ajax 请求以获取完整的 html。
      3. 从 html 中获取标题。
      4. 对标题做任何你想做的事。

      function gettitle(website) {
        if(website.trim() == ''){
         return false;
        }
        var url = 'https://api.codetabs.com/v1/proxy/?quest=' + website;
        $.ajax({
          url: url,
          success: function(responseHtml) {
            var newTitle = $(responseHtml).filter('title').text();
            document.getElementById('title').innerHTML = 'Title: ' + newTitle
          },
          error: function() {
            document.getElementById('title').innerHTML = newTitle = 'Sorry that page doesn\'t';
          }
        });
      }
      <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
      <input placeholder='Website' oninput='gettitle(this.value)' type='url' id='url'>
      <div id='title'></div>

      【讨论】:

      • 您尝试调用的大多数站点都会阻止这种基于 Ajax 的方法,因为它们不允许 CORS 请求。它必须在服务器端完成才能可靠
      • 您可以尝试在各种网站上运行它。它适用于大多数人。
      • 我认为“大多数”还不够可靠。
      • 请提及一些无法运行的网站,我可以改进我的代码。
      • 将网站内容放在创建的 div 块中效率非常低,因为根据网站的不同,浏览器可能需要一段时间来处理它。最好使用正则表达式并解析html。
      猜你喜欢
      • 2011-05-19
      • 2013-04-11
      • 2016-01-15
      • 1970-01-01
      • 2018-01-18
      • 2014-07-08
      • 2011-04-11
      • 2019-03-28
      • 2011-05-19
      相关资源
      最近更新 更多