爬虫,又称spider或者crawler,是一种机器人程序,根据一个或者多个初始的URL地址,抓取并分析这个网页中的内容,通过一定的筛选机制,最终获取所需要的数据。这里的URL可以是普通网页的链接,也可以是app的某些页面。
对于爬虫程序(以及我目前的见识)来说,网页可以分为几种,下面摘取一段互动百科的介绍:
第一种针对以文本和超链接为主的无结构或结构很简单的网页;第二种针对从结构化的数据源(如RDBMS)动态生成的页面,其数据不能直接批量访问;第三种针对的数据界于第一和第二类数据之间,具有较好的结构,显示遵循一定模式或风格,且可以直接访问。
通俗的解释,第一种如百度搜索结果页,要看第二页只能点击最底部的页签;第二种如花瓣网和微博,一页的内容不能一次性获取到,需要不断上拉获取新一批数据。下面先主要介绍一下第一种,数据静态加载的页面。
爬虫抓取数据的步骤通俗点说就两步,找到它,获取它,下面细说。
1.找到它-目标数据在网页中的结构位置及逻辑关系
首先,先看下页面的结构,看看他们的代码是怎么码的。以chrome浏览器为例,在页面右键点击检查,可以进入开发者模式,如下图所示(不同的浏览器可能叫法不一样),这个模式下你可以看到整个页面的结构,包括html/css/js代码、网页的请求收到的数据。然后点击圆圈处的按钮,选中左侧,一行字,右侧面板中的Elements下会同时选中对应的一行代码(简单理解就是,写了这行代码,左侧的页面中就出现了这行文字)。
在左边的列表可以看到很多角括号<>,这些括号里是页面最基本的元素,一般来说一个元素会由两个同样的括号作为起始和结束的标志,括号中间的文字即是显示在网页上的内容,结束标志还会多一个斜杠/,如<p></p>是段落,<a></a>是链接,<li></li>是列表项等。括号内除了元素名称外还会有属性,如<span class="pub-time">7小时前</span>,span元素有个属性名称叫做class,class的属性值是pub-time。
这点很重要,爬虫就是根据元素和其对应的属性值来筛选页面中的内容。
以上图为例提问,我需要获取这个页面中所有的问题及其对应的链接,要如何处理?
通过分析可以发现,所有的问题文本都是遵循一个数据结构(多层嵌套的结构,li中嵌套了两个div和一个span,div嵌套了一个h2,这里不细说),如上图所示。
我们要找的是一个<a>标签中的文本和其中一个叫href的属性值。看一下嵌套的逻辑,li>div(class="news-title")>h2>a。
经过上面的步骤,对于一个常见的页面,我们基本可以很快找到它在网页中的位置以及上下层的逻辑关系了,下面开始第二步~
2.获取它-通过python抓取页面中的数据
环境:mac os
python版本:3.5
IDE:pycharm
第三方模块:BS4(requests是python自带模块,可以直接导入即可)
工欲善其事,必先利其器。PC可能还需要配置环境变量,编辑器也不一定要用pycharm,mac自带shell可以使用(自带的版本是python2.6),PC自带的cmd也可以使用。这些问题先不细说。
开始码代码。
1.导入模块,两个模块分别使用上述两种语法。
import requests
from bs4 import BeautifulSoup
2.获取整个网页
这一步用到了requests模块,把url赋值给一个变量,使用模块中的get函数获取这个url内的数据。
target ='http://www.pmcaff.com/'
content = requests.get(url=target)
html = content.text
这里先看一下运行结果,右侧是运行结果(这一步不需要导入BS4模块)。
我们对比一下,看是不是打印的这个页面的内容。在页面邮件菜单,选择查看源代码,就可以看到构成这个页面的所有代码,打印的结果应该就是所有的内容。
对比看一下,应该是没有问题。
3.获取目标元素
这里就需要用到BS4模块,前面说到了我们要找的<a>标签,它的嵌套层级关系是li>div(class="news-title")>h2>a。
通过查看代码,我们发现每个li下面只有一个类名为"news-title"的div标签,这个标签下有一个没有属性的h2标签,这个h2标签下只有一个a标签。
于是我们知道怎么做了——先找到所有类名为"news-title"的div标签,然后分别把标签内的a提取出来。
3.1获取<div class="news-title"></div>
首先新建一个抓取对象getdiv,BeautifulSoup将在这个对象的范围内进行搜索。使用find_all寻找所有class为"news-title"的div标签,注意class后有个下划线。
getdiv = BeautifulSoup(html,"html.parser") #第一个html是我们定义的变量,"html.parser"指是固定参数不可修改
divtext = getdiv.find_all('div',class_='news-title')
3.2已经把所有的div找出来了,现在找出里面的<a>标签
定义一个变量geta,使搜索范围缩小到之前找到的divtext,这里要转换为字符串,注意后面的参数没有变化。仍旧使用find_all函数找到所有的<a>标签,因为每个div下肯定只有一个a,所以这里a不用再加限制条件进行搜索,如(target = blank)这种。
geta= BeautifulSoup(str(divtext),"html.parser")
atext =geta.find_all('a')
要注意的是,这里找到的是所有的a标签,可以试着打印出来看看,全部是下面这种格式。
<a http://www.pmcaff.com/discuss/index/478578023603264?from=label&pmc_param%5Blabel_name%5D="target="_blank">共享单车跟公共自行车相比的优势在哪里?</a>
4.打印目标元素
提取a标签中的文本和链接,代码如下。
print(atext.string) #打印文本
print(atext.get('href')) #获取href属性并打印出来
.至此,我们就完成任务了,把代码整理一下发出来。
#-*- coding:utf-8 -*-
import requests
from bs4 import BeautifulSoup
if__name__ == '__main__':
target ='http://www.pmcaff.com/'
content = requests.get(url=target)
html = content.text
getdiv = BeautifulSoup(html,"html.parser")
divtext = getdiv.find_all('div',class_='news-title')
geta = BeautifulSoup(str(divtext),"html.parser")
atext = geta.find_all('a')
for each in atext:
print(i,each.string)
print(each.get('href'))
最后上一张运行结果图,成功抓到,bingo!
关于静态加载的页面,已经完成了,不过去pmcaff网站看看,不断下拉是不断有新内容加载出来的,这就涉及到动态加载的问题了,下一篇文章会记录一下如何抓取动态加载的网页数据。
初学中,如有错误欢迎指正,有兴趣的小伙伴可以一起交流学习咯~