Автозаполнение названия сайта по ссылке в форме

<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-адрес веб-сайта, а название веб-сайта должно быть редактируемым, если пользователь этого хочет. Как я могу это сделать? Пожалуйста помоги :(

Пример: когда пользователь вводит https://stackoverflow.com/ URL-адрес в поле «URL-адрес веб-сайта», поле «Заголовок веб-сайта» должно автоматически заполняться как Stack Overflow - Where Developers Learn, Share, &amp; Build Careers.


person Norton VUV    schedule 05.07.2021    source источник
comment
Предполагая, что вы говорите о заголовке, который появляется в строке браузера при просмотре домашней страницы сайта, вам нужно будет сделать http-запрос к URL-адресу, проанализировать возвращаемый html и извлечь из него содержимое элемента заголовка. . Вероятно, не очень практично, поскольку пользователь печатает. Если у вас нет предварительно определенного списка URL-адресов и заголовков в вашей собственной базе данных? (Но тогда, если бы вы это сделали, вы бы использовали раскрывающийся список или элемент управления автозаполнением вместо простого текстового поля)   -  person ADyson    schedule 05.07.2021
comment
Пожалуйста, объясните, что вы подразумеваете под названием веб-сайта и URL-адресом веб-сайта. Это свойство модели?   -  person waterloomatt    schedule 05.07.2021
comment
Как упомянул Эдисон, это может быть довольно сложной задачей. Вам нужно подумать о том, что вызовет выборку. Будет ли включаться при каждом нажатии клавиши? Будете ли вы сначала запускать URL-адрес через какое-либо регулярное выражение, чтобы убедиться, что пользователь не ввел мусор. После того, как у вас есть полезная нагрузка HTML, вам нужно проанализировать ее, чтобы извлечь тег ‹head›‹title›. Это может или не может быть тривиальной задачей. Можете ли вы рассказать нам, что вы пробовали до сих пор или как вы представляете, как это работает?   -  person waterloomatt    schedule 05.07.2021
comment
stackoverflow.com/questions/7901760/ содержит некоторые предложения о том, как это сделать   -  person ADyson    schedule 05.07.2021


Ответы (4)


У вас есть событие change в элементе url-field, которое отправляет запрос на выборку веб-сайту API, который возвращает html-содержимое этого веб-сайта, а затем использует регулярное выражение для извлечения заголовка html, а затем добавляет его в поле имени.

Кроме того, во время выполнения выборки мы показываем текст Fetching, чтобы пользователь знал, что происходит. И событие отправки формы было остановлено функцией preventDefault(). Здесь вы можете делать все, что захотите, после того, как пользователь отправит форму.

Вместо использования https://api.codetabs.com/v1/proxy/?quest=, который ограничит ваши запросы и покажет вам ошибку Too many requests, вы должны использовать свой собственный код, который извлекает содержимое веб-сайта, а затем возвращает ответ. Чтобы оптимизировать это, вы можете вернуть только название веб-сайта, чтобы сэкономить на пропускной способности и циклах процессора.

Причина, по которой вам нужен 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>

person dreamLo    schedule 13.07.2021
comment
выглядит хорошо, два замечания: 1. developer.mozilla. org/en-US/docs/Web/JavaScript/Reference/, чтобы гарантировать, что запрос прокси-API всегда работает, и 2. как и в браузере, я думаю, что у него есть лучший способ анализа HTML, чем регулярное выражение, например DOMDocument и getTagByName;) - person hakre; 16.07.2021
comment
1) Я добавил encodeURI к параметру URL, спасибо. 2) Вы не хотите использовать DOMDocument для анализа документа, потому что веб-сайт может быть очень большим, и вы используете ресурсы для чего-то, что вам не нужно. Вам нужно только извлечь тег заголовка из этого текста, а не анализировать его и извлекать всевозможные данные. Regex в этом случае очень быстрый по сравнению с разбором dom. - person dreamLo; 16.07.2021
comment
Звучит проницательно. Но все же я могу представить, что синтаксический анализатор браузеров для HTML более эффективен, чем регулярное выражение (как в теории), я этого не знаю, но если использовать частичное содержимое (например, первые 4096 байтов или около того), это может дополнительно оптимизировать его ( то же самое для подхода регулярных выражений). Может быть, это приятное место. В целом: это были просто замечания, без запроса на редактирование ответа, больше для вашего сведения (сегодня больше не могу голосовать за ваш комментарий, извините). - person hakre; 16.07.2021
comment
Дом браузера более эффективен, чем регулярное выражение, если вы хотите извлечь все. Но если вам нужно только одно, то регулярное выражение выигрывает. - person dreamLo; 16.07.2021
comment
ну не так уверен. если вам нужно будет проанализировать HTML с помощью регулярного выражения с начала строки, я не уверен, что это быстрее. регулярное выражение здесь, например, не учитывает пробелы в открывающем теге заголовка, например (ни атрибуты). Наверняка выиграет (возможно, поиск строки даже быстрее, видя шаблон, вполне выполнимый также для поиска по закрывающему тегу). - person hakre; 16.07.2021
comment
@dreamLo Это работает! но с некоторыми сайтами это не так. Например; binance.com - person Norton VUV; 18.07.2021
comment
@NortonVUV Это из-за регулярного выражения, оно не учитывало <title foo="bar"></title>. Я исправил регулярное выражение, так что теперь binance.com тоже работает. - person dreamLo; 18.07.2021
comment
@dreamLo, пожалуйста, проверьте и этот URL: digital-investment.org - person Norton VUV; 18.07.2021
comment
Теперь регулярное выражение должно работать для любого типа пробелов внутри <title>, а также есть обработка ошибок, когда заголовок просто не выходит на страницу. - person dreamLo; 19.07.2021
comment
@dreamLo tysm за помощь ++ - person Norton VUV; 20.07.2021

Потому что вы, например, похожи на 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);
    }
}
person While1    schedule 14.07.2021

Как только пользователь ввел данные.

Получите значение, используя $("#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);
person Danyal Sandeelo    schedule 13.07.2021

Вот как:

  1. Прочтите адрес веб-сайта.
  2. Отправьте ajax-запрос к codetabs api, чтобы получить полный 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>

person Keshav Bajaj    schedule 13.07.2021
comment
Большинство сайтов, на которые вы пытаетесь позвонить, блокируют этот подход на основе Ajax, потому что они не разрешают запросы CORS. Это должно быть сделано на стороне сервера, чтобы быть надежным - person ADyson; 13.07.2021
comment
Вы можете попробовать запустить его с различными веб-сайтами. Это работает с большинством из них. - person Keshav Bajaj; 13.07.2021
comment
Я бы предположил, что большинство из них недостаточно надежны. - person ADyson; 13.07.2021
comment
Пожалуйста, укажите некоторые из веб-сайтов, которые не работают, чтобы я мог улучшить свой код. - person Keshav Bajaj; 13.07.2021
comment
Крайне неэффективно размещать содержимое веб-сайта в созданном блоке div, потому что в зависимости от веб-сайта браузеру может потребоваться некоторое время для его обработки. Лучше использовать регулярное выражение и анализировать html. - person dreamLo; 14.07.2021
comment
@ADyson В зависимости от использования этого приложения отправка запроса сервер-сервер также имеет свои ограничения: если количество пользователей, заходящих на определенный веб-сайт, увеличивается, с сервера на этот веб-сайт будет отправлено огромное количество запросов, поэтому IP-адрес сервера будет занесен в черный список. Есть и другие параметры, например, вопросы конфиденциальности. Вообще говоря, обработка этого на стороне сервера лучше, чем на фронте, но для этого нет лучшего решения :) - person Mohsen Nazari; 16.07.2021