Python网络爬虫无法找到存在的关键字

时间:2017-02-27 15:04:53

标签: python html web-scraping web-crawler

我正在尝试抓取多个网站(使用python 2.7)来查明特定关键字是否在其中退出。我的代码:

import urllib2
import csv

fieldnames = ['Website', '@media', 'googleadservices.com/pagead/conversion.js', 'googleadservices.com/pagead/conversion_async.js']

def csv_writerheader(path):
    with open(path, 'w') as csvfile:
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames, lineterminator='\n')
        writer.writeheader()

def csv_writer(dictdata, path):
    with open(path, 'a') as csvfile:
        writer = csv.DictWriter(csvfile, fieldnames=fieldnames, lineterminator='\n')
        writer.writerow(dictdata)

csv_output_file = 'EXPORT_Results!.csv'
# LIST OF KEY WORDS (TITLE CASE TO MATCH FIELD NAMES)
keywords = ['@media', 'googleadservices.com/pagead/conversion.js', 'googleadservices.com/pagead/conversion_async.js']

csv_writerheader(csv_output_file)

with open('top1m-edited.csv', 'r') as f:
    csv_f = csv.reader(f, lineterminator='\n')
    for line in f:
        strdomain = line.strip()
        # INITIALIZE DICT
        data = {'Website': strdomain}

        if '.nl' in strdomain:
            try:
                req = urllib2.Request(strdomain.strip())
                response = urllib2.urlopen(req)
                html_content = response.read()

                # ITERATE THROUGH EACH KEY AND UPDATE DICT
                for searchstring in keywords:
                    if searchstring.lower() in str(html_content).lower():
                        print (strdomain, searchstring, 'found')
                        data[searchstring] = 'found'
                    else:
                        print (strdomain, searchstring, 'not found')
                        data[searchstring] = 'not found'

                # CALL METHOD PASSING DICT AND OUTPUT FILE
                csv_writer(data, csv_output_file)

            except urllib2.HTTPError:
                print (strdomain, 'HTTP ERROR')

            except urllib2.URLError:
                print (strdomain, 'URL ERROR')

            except urllib2.socket.error:
                print (strdomain, 'SOCKET ERROR')

            except urllib2.ssl.CertificateError:
                print (strdomain, 'SSL Certificate ERROR')

f.close()

然而,我的爬虫在这件事上似乎不太准确。

例如:我正在抓取网站列表,以确定它们的源代码中是否包含@mediagoogleadservices.com/pagead/conversion_async.js等关键字。脚本运行完毕后,我手动检查结果的准确性。手动检查后(通过Chrome使用Inspect Element搜索网址源代码中的关键字)我发现某些网站的源代码中包含@media和/或googleadservices.com/pagead/conversion_async.js,而我的抓取工具说这些网站不包含这些关键字。

这可能与使用Chrome" Inspect Element"找到网站代码这一事实有关。没有完全匹配使用Chrome" View-source"找到的代码(同一网站)。例如,this网站在其" Inspect Element" -code中包含googleadservices.com/pagead/conversion_async.js,但未包含在其#34; View-source" -code中。

我的问题:可能是我的抓取工具纯粹是在搜索网站的视图源代码而不是他们的" Inspect Element" -codes(它应该在哪里)正在寻找)?

如果这是我的问题,我该如何解决?

1 个答案:

答案 0 :(得分:2)

因为网页的源代码以及启动Chrome Web Developer所看到的内容是两个不同的东西

为什么?源代码是服务器发送的原始HTML页面。您在Chrome Web Developer或Firebug中看到的内容(例如,通过单击“Inspect Element”)是页面的文档对象模型(DOM):您的浏览器已解析的源代码它已经启动了JavaScript元素。

但Javascript可以在不触及源代码的情况下完全修改页面。

Here is an example.通过点击“更改内容”,您将看到网页内容(在右侧窗口中)已完全更改,而源代码(在左侧窗口中)仍然相同。

在您的示例googleadservices.com/pagead/conversion_async.js中,async术语是该页面使用AJAX(异步Javascript和XML)技术加载元素的线索。

因此,您需要一个可以处理JavaScript的Python脚本。有几种可能性,例如使用Selenium或Dryscrape模块。

以下是Selenium,BeautifulSoup(在搜索前解析HTML)和正则表达式(因为您正在搜索文本中的单词,而不是特定的HTML元素)的基本慢速示例

from bs4 import BeautifulSoup
from selenium import webdriver
import re

def get_keywords(source_url, keywords):
    driver = webdriver.Firefox()
    driver.get(source_url)
    html = driver.page_source
    soup = BeautifulSoup(html, "html.parser")
    for names in keywords:
        re.escape(names)
    search = "(" + "|".join(keywords) + ")"
    pattern = re.compile(search)
    print(pattern.findall(str(soup)))
    driver.quit()       

keywords = ['https://www.rocmn.nl/roc-midden-nederland', 'googleadservices.com/pagead/conversion.js', 'googleadservices.com/pagead/conversion_async.js']

get_keywords('https://www.rocmn.nl/', keywords)

输出:

['https://www.rocmn.nl/roc-midden-nederland', 'googleadservices.com/pagead/conversion_async.js']