<p>I'm writing a PHP script that involves scraping web pages. Currently, the script analyzes the page line by line, but it breaks if there is a tag that spans multiple lines, like </p>

<pre><code>&lt;img src="example.jpg"
alt="example"&gt;
</code></pre>

<p>If worse comes to worst, I could possibly preprocess the page by removing all line breaks, then re-inserting them at the closest <code>&gt;</code>, but this seems like a kludge.</p>

<p>Ideally, I'd be able to detect a tag that spans lines, conjoin only those to lines, and continue processing.<br>
So what's the best method to detect this?</p>

[{'answer_id': 33835, 'author': 'Jon Limjap', 'author_id': 372, 'author_profile': 'https://Stackoverflow.com/users/372', 'pm_score': 1, 'selected': False, 'text': "<p>Well, this doesn't answer the question and is more of an opinion, but...</p>\n\n<p>I think that the best scraping strategy (and consequently, to eliminate this problem) is not to analyze an HTML line by line, which is unnatural to HTML, but to analyze it by its natural delimiter: &lt;> pairs.</p>\n\n<p>There will be two types of course:</p>\n\n<ul>\n<li>Tag elements that are immediately closed, e.g., &lt; br /></li>\n<li>Tag elements that need a separate closing tag, e.g., &lt; p > text &lt; /p ></li>\n</ul>\n\n<p>You can immediately see the advantage of using this strategy in the case of paragraph(p) tags: It will be easier to parse mutiline paragraphs instead of having to track where the closing tag is. </p>\n"}, {'answer_id': 33839, 'author': 'Jörg W Mittag', 'author_id': 2988, 'author_profile': 'https://Stackoverflow.com/users/2988', 'pm_score': 3, 'selected': False, 'text': '<p>This is one of my pet peeves: <em>never</em> parse HTML by hand. <em>Never</em> parse HTML with regexps. <em>Never</em> parse HTML with string comparisons. <em>Always</em> use an HTML parser to parse HTML\xa0– that\'s what they\'re there for.</p>\n\n<p>It\'s been a long time since I\'ve done any PHP, but a quick search turned up <a href="http://SimpleHTMLDom.SourceForge.Net/" rel="noreferrer" title="PHP Simple HTML DOM">this PHP5 HTML parser</a>.</p>\n'}, {'answer_id': 33841, 'author': 'Josh', 'author_id': 257, 'author_profile': 'https://Stackoverflow.com/users/257', 'pm_score': 2, 'selected': False, 'text': '<p>Don\'t write a parser, use someone else\'s: <a href="http://www.php.net/manual/en/domdocument.loadhtml.php" rel="nofollow noreferrer">DOMDocument::loadHTML</a> - that\'s just one, I think there are a lot of others.</p>\n'}, {'answer_id': 33875, 'author': 'corymathews', 'author_id': 1925, 'author_profile': 'https://Stackoverflow.com/users/1925', 'pm_score': 0, 'selected': False, 'text': "<p>Why don't you read in a line, and set it to a string, then check the string for tag openings and closings, If a tag spans more then one line add the next line to the string and move the part before the opening brace to your processed string. Then just parse through the entire file doing this. Its not beautiful but it should work.</p>\n"}, {'answer_id': 34602, 'author': 'ceejayoz', 'author_id': 1902010, 'author_profile': 'https://Stackoverflow.com/users/1902010', 'pm_score': 0, 'selected': False, 'text': '<p>If you\'ve gotta stick to your current method of parsing, and it\'s a regex, you can use the <a href="http://us3.php.net/manual/en/reference.pcre.pattern.modifiers.php" rel="nofollow noreferrer">multi-line flag</a> "m" to span across multiple lines.</p>\n'}, {'answer_id': 34614, 'author': 'Factor Mystic', 'author_id': 1569, 'author_profile': 'https://Stackoverflow.com/users/1569', 'pm_score': 2, 'selected': True, 'text': "<p>Perhaps for future projects I'll use a parsing library, but that's kind of aside from the question at hand. This is my current solution. <code>rstrpos</code> is strpos, but from the reverse direction. Example use:</p>\n\n<pre><code>for($i=0; $i&lt;count($lines); $i++)\n{\n    $line = handle_mulitline_tags(&amp;$i, $line, $lines);\n}\n</code></pre>\n\n<p>And here's that implementation:</p>\n\n<pre><code>function rstrpos($string, $charToFind, $relativePos)\n{\n    $searchPos = $relativePos;\n    $searchChar = '';\n\n    while (($searchChar != $charToFind)&amp;&amp;($searchPos&gt;-1))\n    {\n        $newPos = $searchPos-1;\n        $searchChar = substr($string,$newPos,strlen($charToFind));\n        $searchPos = $newPos;\n    }\n\n    if (!empty($searchChar))\n    {\n        return $searchPos;\n        return TRUE;\n    }\n    else\n    {\n        return FALSE;\n    }\n}\n\nfunction handle_multiline_tags(&amp;$i, $line, $lines)\n{\n    //if a tag is opened but not closed before a line break,\n\n    $open = rstrpos($line, '&lt;', strlen($line));\n    $close = rstrpos($line, '&gt;', strlen($line));\n    if(($open &gt; $close)&amp;&amp;($open &gt; -1)&amp;&amp;($close &gt; -1))\n    {\n        $i++;\n        return trim($line).trim(handle_multiline_tags(&amp;$i, $lines[$i], $lines));\n    }\n    else\n    {\n        return trim($line);\n    }\n}\n</code></pre>\n\n<p>This could probably be optimized in some way, but for my purposes, it's sufficient.</p>\n"}]
['https://Stackoverflow.com/questions/33814', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/1569/']