#scan внезапно возвращает пустой массив

#ruby #web-scraping #nokogiri

#ruby #очистка веб-страниц #nokogiri

Вопрос:

Я создаю скребок для статей из www.dev.to , который должен быть указан в названии, авторе и тексте статьи. Я использую #scan, чтобы избавиться от пробелов и других символов после имени автора. Сначала я предположил, что имя автора будет состоять из имени и фамилии, затем понял, что у некоторых указано только одно имя. Теперь, когда я соответствующим образом изменил регулярное выражение, метод перестал работать, и #scan возвращает пустой массив. Как я могу это исправить?

   def scrape_post(path)
    url = "https://dev.to/#{path}"
    html_content = open(url).read
    doc = Nokogiri::HTML(html_content)
    doc.search('.article-wrapper').each do |element|
      title = element.search('.crayons-article__header__meta').search('h1').text.strip
      author_raw = element.search('.crayons-article__subheader').text.strip
      author = author_raw.scan(/Aw (s|w)w /).first
      body = doc.at_css('div#article-body').text.strip
      @post = Post.new(id: @next_id, path: path, title: title, author: author, body: body, read: false)
    end
    @post
  end
  

Пример входных данных:

 path = rahxuls/preventing-copying-text-in-a-webpage-4acg
  

Ожидаемый результат:

 title = "Preventing copying text in a webpage 😁"

author_raw = "Rahuln              nn              n                  Nov  6nnn                ・2 min read"

author = "Rahul"
  

Комментарии:

1. Не могли бы вы добавить несколько примеров входных данных и ожидаемый результат?

2. будет сделано! секундочку

3. Включало ли изменение, которое вы внесли в свое регулярное выражение, добавление круглых скобок в середину?

4. да. я сделал это на случай, если есть только одно имя, а не имя фамилия. у вас есть предложение, как я могу его изменить?

5. Почему бы не выбрать элемент / узел, который содержит только имя? author = element.search('.crayons-article__subheader a').text.strip #=> "Rahul"

Ответ №1:

Из scan документации.

Если шаблон не содержит групп, каждый отдельный результат состоит из совпадающей строки, $amp; . Если шаблон содержит группы, каждый отдельный результат сам по себе является массивом, содержащим одну запись на группу.

Добавив круглые скобки в середину вашего регулярного выражения, вы создали группу захвата. Сканирование вернет все, что захватывает эта группа. В приведенном вами примере так и будет 'u' .

 "Rahuln nn n Nov 6nnn ・2 min read".scan(/Aw (s|w)w /) #=> [["u"]]
  

Группа может быть помечена как не захватываемая, чтобы вернуться к вашей старой реализации

 "Rahuln nn n Nov 6nnn ・2 min read".scan(/Aw (?:s|w)w /) #=> ["Rahul"]
#                                                       ^
  

Или вы можете добавить именованную группу захвата к тому, что вы на самом деле хотите извлечь.

 "Rahuln nn n Nov 6nnn ・2 min read".match(/A(?<name>w (s|w)w )/)[:name] #=> "Rahul"
  

Комментарии:

1. спасибо 🙂 я очень новичок в регулярных выражениях, и это многое объясняет!