您是否曾经想过以编程方式从网站上捕获特定信息以进行进一步处理?说些体育成绩,股市趋势或最新时尚,比特币和其他加密货币价格?如果网站上提供了您所需的信息,则可以编写搜寻器(也称为“刮板"或“蜘蛛")来浏览网站并提取所需的内容。让我们找出如何在python中执行此操作。
请注意,有些网站不鼓励使用搜寻器来访问该网站提供的信息。因此,在任何网站上部署搜寻器之前,请先检查网站条款。
安装Scrapy
我们使用名为Scrapy的python模块来处理实际的搜寻。它快速,简单,并且可以像使用浏览器一样浏览多个网页。
但是请注意,scrapy没有在浏览网站时处理javascript的功能。因此,使用这种方法无法正确地抓取那些使用JavaScript操纵用户界面的网站和应用。
现在让我们安装scrapy。我们使用virtualenv安装scrapy。这使我们可以在目录中安装scrapy,而不会影响其他系统安装的模块。
创建目录并在该目录中初始化虚拟环境。
mkdir crawlercd crawlervirtualenv venv. venv/bin/activate
您现在可以在其中安装scrapy目录。
pip install scrapy
检查是否正确安装了scrapy。
scrapy# printsScrapy 1.4.0 - no active projectUsage: scrapy <command> [options] [args]Available commands: bench Run quick benchmark test fetch Fetch a URL using the Scrapy downloader genspider Generate new spider using pre-defined templates runspider Run a self-contained spider (without creating a project)...
构建网站爬网程序(也称为蜘蛛)
现在让我们为加载一些信息。我们首先从https://en.wikipedia.org/wiki/Battery_(electricity)电池上的Wikipedia页面上获取一些信息。
编写搜寻器的第一步是定义一个python从 scrapy.Spider 扩展的类。让我们将此类称为 spider1 。
蜘蛛类至少需要满足以下条件:
import scrapyclass spider1(scrapy.Spider): name = 'Wikipedia' start_urls = ['https://en.wikipedia.org/wiki/Battery_(electricity)'] def parse(self, response): pass
我们现在可以运行此蜘蛛以确保一切正常。它的运行方式如下。
scrapy runspider spider1.py# prints2017-11-23 09:09:21 [scrapy.utils.log] INFO: Scrapy 1.4.0 started (bot: scrapybot)2017-11-23 09:09:21 [scrapy.utils.log] INFO: Overridden settings: {'SPIDER_LOADER_WARN_ONLY': True}2017-11-23 09:09:21 [scrapy.middleware] INFO: Enabled extensions:['scrapy.extensions.memusage.MemoryUsage', 'scrapy.extensions.logstats.LogStats',...
关闭日志记录
如您所见,使用最小类运行scrapy会产生一堆输出,这对我们来说没有太大意义。让我们将日志记录级别设置为 warning 并重试。将以下行添加到文件的开头。
import logginglogging.getLogger('scrapy').setLevel(logging.WARNING)
重新运行蜘蛛程序后,我们应该会看到最少的日志消息。
使用Chrome检查器
从网页中提取信息包括确定我们要从中获取信息的HTML元素的位置。在Chrome Web浏览器中查找元素位置的一种简便方法是使用检查器。
这会弹出开发者控制台,并选择 Elements 标签。在标签下方,您应该看到状态栏,其中元素的位置如下所示:
html body div#content.mw-body h1#firstHeading.firstHeading 。
如下所述,您需要该职位的部分或全部。
提取标题
现在让我们向添加一些代码parse()方法以提取页面标题。
... def parse(self, response): print response.css('h1#firstHeading::text').extract()...
该方法的 response 参数支持一种称为 css(),它将使用给定位置从页面中选择元素。对于我们的情况,该元素为 h1.firstHeading 。我们需要元素的文本内容,因此将 :: text 添加到选择中。最后, extract()方法返回选定的元素。
在该类上再次运行scrapy时,我们得到以下输出:
[u'Battery (electricity)']
This显示标题已提取到Unicode字符串列表中。
说明如何?
为演示从网页提取数据的更多方面,让我们获得第一段
在使用Chrome开发者控制台进行检查时,我们发现元素的位置为(右尖括号(>)表示元素之间的父子关系) ):
div#mw-content-text> div> p
此位置返回全部 p 元素匹配,其中包括整个描述。由于只需要第一个 p 元素,因此我们使用以下提取器:
response.css('div#mw-content-text>div>p')[0]
要仅提取文本内容,我们添加CSS提取器 :: text :
response.css('div#mw-content-text>div>p')[0].css('::text')
最后一个表达式使用 extract()返回一个unicode字符串列表。我们使用python join()函数加入列表。
def parse(self, response): print ''.join(response.css('div#mw-content-text>div>p')[0].css('::text').extract())
我们正在寻找使用此类运行scrapy的输出:
An electric battery is a device consisting of one or more electrochemical cells with external connections provided to power electrical devices such as flashlights, smartphones, and electric cars.[1] When a battery is supplying electric power, its positive terminal is...
收集数据上面的代码将提取的数据打印到控制台。当需要以JSON格式收集数据时,可以使用 yield 语句。 yield 的工作方式如下-执行包含 yield 语句的函数会将调用方称为生成器。生成器是调用者可以重复执行直到终止的函数。
这里的代码类似于上面的代码,但是使用 yield 语句返回 p 元素。
... def parse(self, response): for e in response.css('div#mw-content-text>div>p'): yield { 'para' : ''.join(e.css('::text').extract()).strip() }...
您现在可以通过指定输出JSON文件来运行Spider,如下所示:
scrapy runspider spider3.py -o joe.json
生成的输出如下:<
[{"para": "An electric battery is a device consisting of one or more electrochemical cells with external connections provided to power electrical devices such as flashlights, smartphones, and electric cars.[1] When a battery is supplying electric power, its positive terminal is the cathode and its negative terminal is the anode.[2] The terminal marked negative is the source of electrons that when connected to an external circuit will flow and deliver energy to an external device. When a battery is connected to an external circuit, electrolytes are able to move as ions within, allowing the chemical reactions to be completed at the separate terminals and so deliver energy to the external circuit. It is the movement of those ions within the battery which allows current to flow out of the battery to perform work.[3] Historically the term \"battery\" specifically referred to a device composed of multiple cells, however the usage has evolved additionally to include devices composed of a single cell.[4]"},{"para": "Primary (single-use or \"disposable\") batteries are used once and discarded; the electrode materials are irreversibly changed during discharge. Common examples are the alkaline battery used for flashlights and a multitude of portable electronic devices. Secondary (rechargeable) batteries can be discharged and recharged multiple...
处理信息的多个位
现在让我们看一下提取与信息相关的多个位。在此示例中,我们将提取当前周末的热门IMDb票房收入。可以在http://www.imdb.com/chart/boxoffice的表中找到此信息,该表中包含每个匹配项的信息行。
我们使用以下 parse()方法。再次如上所述,使用Chrome开发者控制台确定了CSS元素的位置:
运行蜘蛛现在会返回以下JSON:
[{"gross": "$93.8M", "weeks": "1", "weekend": "$93.8M", "image": "https://images-na.ssl-images-amazon.com/images/M/MV5BYWVhZjZkYTItOGIwYS00NmRkLWJlYjctMWM0ZjFmMDU4ZjEzXkEyXkFqcGdeQXVyMTMxODk2OTU@._V1_UY67_CR0,0,45,67_AL_.jpg", "title": "Justice League"},{"gross": "$27.5M", "weeks": "1", "weekend": "$27.5M", "image": "https://images-na.ssl-images-amazon.com/images/M/MV5BYjFhOWY0OTgtNDkzMC00YWJkLTk1NGEtYWUxNjhmMmQ5ZjYyXkEyXkFqcGdeQXVyMjMxOTE0ODA@._V1_UX45_CR0,0,45,67_AL_.jpg", "title": "Wonder"},{"gross": "$247.3M", "weeks": "3", "weekend": "$21.7M", "image": "https://images-na.ssl-images-amazon.com/images/M/MV5BMjMyNDkzMzI1OF5BMl5BanBnXkFtZTgwODcxODg5MjI@._V1_UY67_CR0,0,45,67_AL_.jpg", "title": "Thor: Ragnarok"},...]
使用履带
现在,让我们以一些要点来结束本文:
您是否有任何特定的网站抓取有哪些项目?您尝试将其付诸实施时遇到什么问题?请在下面的评论中告知我们。
图片来源:dxinerz / Depositphotos | Lulzmango / Wikimedia Commons