1、1数据科学导论 第十六章 网络抓取/网络爬虫入门2主要内容一 引言二 HTML网页结构三 网络抓取的步骤四 网络爬虫的若干案例五 表格数据爬取3一 引言4目 的浏览器上看到的页面背后是HTML形式的非结构化数据.(unstructured data)目的是把网络上的这些非结构化数据中所需要的信息提取出来.网络抓取(web scraping)泛指从网页的各个部分利用编程来获得需要的信息,在国内,网络抓取往往被称为网络爬虫(web crawler).特别要说明的是本书不是网络爬虫的专门教材,本章的内容仅供读者入门参考,我们抓取的数据均来自网络上公开的信息,数据量较小,仅以教学为目的,我们希望所有读
2、者也能遵循这一原则,合理、合法且高效地获取公开的数据集.5手 段 人们可以通过几乎所有的编程语言来实行网络抓取,甚至还可以使用Google Docs.我们将使用Python 和R 两种语言通过相对简单的实际例子来介绍网络抓取的过程.使用R 来入门网络抓取会比较容易,但做更复杂的网络抓取就不那么容易.使用Python做网络抓取,如果对网络结构不熟悉,一开始可能会稍微慢些,但随着时间的推移,会觉得越来越得心应手.6二 HTML网络结构7HTML HTML 为超文本标记语言(hyper text markup language)的英文首字母缩写,用于创建网页的基本结构元素.这意味着它通过结构和语义信
3、息来“标记”文档中的内容,以指示浏览器如何显示页面.图16.1不列颠百科全书的页面(左)及其HTML代码(右)8HTML 一个基本的网站页面通常由三种类型的代码构成:HTML 控制结构元素(structural elements);CSS(cascading style sheets)给这些元素赋以样式(style);JavaScript 使得这些元素之间能够有动态互动(dynamic interaction).比如,字体或图形及各种元素的颜色及大小等由CSS 确定,而不同内容和不同网页之间的交互链接及人机对话则由JavaScript 控制,而总的结构由HTML 定义.9网页代码 包含在符号“
4、”之间的内容为注释,开始符为“”,结束符为“”.练习网页练习网页 第第1级标题级标题 标题一共有标题一共有6级级 第第6级标题级标题 这是加了这是加了(加大字号加大字号,中心化的中心化的)样式的另一段样式的另一段 中国人民大中国人民大 10网页显示 作为前面代码实现的图16.2有第1 和第6 级标题及标题下面的文字.所有字的大小,位置的安排等都是由上面代码决定的.图16.2 前面HTML代码相应的页面11元素和标签的语法标签:在前面网页的代码中,符号及称为标签(tag),其中为开始标签,而为结束标签.元素:而标签中的内容,比如html(或)、body(或)、p(或)称为元素(element).
5、网页主要是三个基本结构元素组成:html,head,及body.最近一些年又发展出一些新的结构元素,包括header,main,nav,article,section,aside,address,footer.12元素和标签的语法 网页标题网页标题 这是一个文字段落这是一个文字段落.开始的 为文档类型声明,作用就是为浏览器提供一项信息,即HTML是用什么版本编写的.和之间为文本描述网页.与之间是可见的页面内容.标记的文本网页标题定义了在浏览器中显示的页面名字,但不在页面显示.13分层嵌套结构网页的结构是分层的,而且一层套一层.上面基本网络中,作为根元素(root element)的html 为
6、body 和head 的父母(parent),而元素title 和p 分别是head 和body 的儿女(children),也是html 的后代(descendant),body 与head、title与p 又是兄弟姐妹(sibling).html 是所有其他元素的祖先(ancestor).这里代码的缩进显示各层的嵌套关系.14头元素(head)中的样式元素head 可以包含许多html 元素,这些元素不是浏览器呈现的页面的可见部分.这些元素是描述有关页面的信息,有base、link、meta、noscript、script、style、template、title,而title 是必须有的
7、.下页代码及图16.3显示了在head 元素中设置了样式style 的效果.15头元素(head)中的样式This is a titleh2.wu2 color:red;/*h2标题的颜色标题的颜色*/*具有具有id 为为AC 的样式的样式(style)*/#AC background-color:Orange;color:MediumSeaGreen;padding:25px;text-align:center;/*所有具有类所有具有类(class)名字名字mytown 的样式的样式*/.mytown background-color:DodgerBlue;color:white;paddi
8、ng:20px;难得糊涂难得糊涂天下为公天下为公 访问天下为公访问天下为公 广东广东图16.3 左边HTML代码相应的页面16头元素(head)中的样式下面是对上面与图16.3相关的一些代码的解释:h2.wu2 color:red;表示标了class=wu2 的h2 标题都是红色;代码#AC background-color:Orange;color:MediumSeaGreen;padding:25px;text-align:center;表示凡是标了id=“AC”的元素(这里是“天下为公”)字段都是橘黄背景、中海绿颜色字体、25px 大小、居中放置.表示点击该字段后会跳id=“AC”的元素
9、.mytown background-color:DodgerBlue;color:white;padding:20px;表示标class=“mytown”的元素有奇蓝背景,白字体,20px 大小.17网络元素汇总除了确定网页三个组成部分的元素html,head,及body 之外,还有很多其他的HTML元素,下面做一个简要的汇总:根元素(root element)文档元数据(document metadata)head 提供一般信息(元数据),包括标题、链接、代码、样式等等;base 指定一个基本URL,为文档中包含的所有相关的URL 使用;link 指定了指向其他外部资源的链接;meta 提
10、供有关HTML 文档不显示的描述其他信息的元数据;style 指定文档的样式,也可以链接到外部样式表;title 定义文档标题(只能有一个);18网络元素汇总body 定义HTML 文档的正文,包含文档的所有内容内容的划分部分 address 定义文档(如在body 内)或文章(如在article 内)作者、主人的联系信息;article 指独立的内容;aside 定义了与主要问题有关但又只能作旁白的内容;footer 可包含作者、版权信息、或者到其他页面的链接;header 一般包含引入相关页面的内容;h1,h2,h3,h4,h5,h6 为6 个水平的节标题,h1 最高;19网络元素汇总 m
11、ain 包含文档主要内容;nav 定义了一组导航链接,仅用于主要的导航链接块,并非文档的所有链接都应位于nav 元素中;section 包含文档的节(而div 仅涉及一页的节);文本内容 p 表示一个段落;blockquote放在块中的成段引言,其他引言放在元素标签 中;div 标记定义文档中的分区或节;pre 定义预先格式化的文本;在网页画一条水平线;20网络元素汇总 dl、dt、dd 在一起定义列表,比如下面左边的代码对应于右边的效果:ol、ul、li 显示列表 的代码和效果如右图:21网络元素汇总行内文本语义部分,定义单词、行或任意文本的含义、结构或样式图片和多媒体嵌入式内容部分脚本部分
12、,主要是为了创建动态内容和网络应用程序编辑记录表格的内容,这里的元素用于创建和处理表格数据22HTML的属性HTML 属性(HTML attribute)是在开始标记中用来控制元素行为的特殊单词,属于元素类型的修饰符.id 属性可用在任何地方,作为一个元素的唯一识别符;class 属性可以在任何HTML 元素上使用,它为一个元素指定一个或多个名称;在元素 中的href 属性,给出与链接地址有关的名词;在图形元素 中的src、height、width 以及alt 分别标明图形的位置(src 必须有)、高度、宽度以及(如果原先的图片不存在)备用文字;表示样式的style 属性用于指定元素的样式,如
13、颜色、字体、大小等;被添加到 元素的title 属性使得鼠标悬停在该段落时会显示其值.23三 网络抓取的步骤24网络抓取的步骤找到目标URL.URL(uniform resource locator)就是网址(web address)的俗称,典型的URL 可以有下面形式:http:/ 的结构.有时需要使用浏览器(我们用Chrome浏览器)的开发人员工具来检查网站的HTML 结构;通过网络抓取的代码获得网络结构;从众多信息中挑选出需要的内容.25例16.1:联合国宪章抓取我们将抓取联合国宪章的全部文本,并存入文件中;使用Python来抓取,具有直观性、易用性和丰富的生态系统,有Beautiful
14、Soup、requests、urllib、scrapy 等模块来协助这项任务;requests(urllib.request 也类似)可以用来访问网站,以达到获取数据、发布数据或分析数据的目的;BeautifulSoup 可以从网页中提取信息,比如:提取表、列表、段落,还可以放置筛选器来从网页中提取信息;下载requests 及BeautifulSoup4:pip install requests BeautifulSoup426例16.1:联合国宪章抓取打开联合国中文网址(URL):http:/www.un.org/zh/,为联合国主地名,通过选择得到联合国宪章序言部分的页面图16.4 联合
15、国宪章中文网页序言部分27例16.1:联合国宪章抓取这个网页本身并不包括联合国宪章其他章节,必须依靠点击相应的字符来达到所要的章节;利用浏览器(这里用的是Chrome 浏览器)的网络功能,依次点中序言、各章、及各个部分,发现各章节的地址都是联合国主地名加上具体的分支地名组成,比如第一章的网址:http:/www.un.org/zh/sections/un-charter/chapter-i/index.html它为联合国主地名 http:/www.un.org/zh/加上 sections/un-charter/chapter-i/index.html 28例16.1:联合国宪章抓取首先,载入
16、需要的Python 模块:from bs4 import BeautifulSoupimport requests然后用requests 获得联合国宪章首页的网页信息,并用Beautiful Soup 来提取网页细节:page=requests.get(http:/www.un.org/zh/charter-united-nations/)soup=BeautifulSoup(page.content,html.parser)29例16.1:联合国宪章抓取 所有关于宪章的具体内容都在类 的子元素中的链接元素 中Link=soup.find_all(div,class_=content)0.fi
17、nd_all(a)每个元素都是提取出来的HTML 中的全部内容,但我们需要的仅仅是其中的网址,因此要对Link 的每个元素提取网址:UN=http:/www.un.org/zh/hr=list()for link in Link:hr.append(UN+link.get(href)hr=hr2:22#只有只有2到到22是有关的地址是有关的地址30例16.1:联合国宪章抓取 由于局部地址有形式./,因此要把它去掉:for i in range(len(hr):hri=hri.replace(/./,/)通过网页Chrome浏览器的Inspect 功能,发现:所有页中内容都在元素 的后代元素中;
18、在第一个包括序言的网址(hr0),文字内容会在元素“li”,“h3”,“h4”,“p”之中(但“主页”二字也出现在“li”);在剩下的的19 页,文字内容会仅在元素“h3”,“h4”,“p”之中.31例16.1:联合国宪章抓取 比如,对于第1页(hr0),使用下面程序可打印出网页内容:r=requests.get(hr0)sp=BeautifulSoup(r.content,html.parser)s_div=sp.find_all(section,class_=col-sm-9)0s_p=s_div.find_all(li,h3,p)打印其他页需修改:s_p=s_div.find_all(h
19、3,p)32例16.1:联合国宪章抓取 汇总起来,所有网页的抓取和存储代码为:with open(UNCharter.txt,w)as text_file:for k in range(len(hr):r=requests.get(hrk)sp=BeautifulSoup(r.content,html.parser)s_div=sp.find_all(section,class_=col-sm-9)0if k=0:s_p=s_div.find_all(h3,li,h4,p)else:s_p=s_div.find_all(h3,h4,p)for i in s_p:i=i.stringsif k=
20、0:i=.join(i).strip(主页主页)else:i=.join(i)print(i,file=text_file)这样,全部联合国宪章内容都以文本形式存入文件UNCharter.txt 之中.33例16.1:联合国宪章抓取使用R软件,程序包为rvest;第一步:获取网址的代码:library(rvest)preface=http:/www.un.org/zh/sections/un-charter/preamble/index.htmlhttr_web-read_html(preface,encoding=utf-8)第二步:下载rvest 所需要的工具软件SelectorGadge
21、t;第三步:在打开联合国宪章网页之后,点击工具图标,选中所需要的内容,选中的内容会变色,在右下面会有某些代码出现,这里是“.region-content”34例16.1:联合国宪章抓取复制该代码粘贴在函数html_node 中,并得到序言页的文字:res=html_node(.region-content)res=html_text(res)最后,把这个字符串转换为文本,并存入文件.图16.5 用SelectorGadget 获取CSS 代码图35例16.1:联合国宪章抓取完整的代码:library(rvest)library(tidyverse)preface=http:/www.un.or
22、g/zh/sections/un-charter/preamble/index.html#序言页网址序言页网址ch=paste0(http:/www.un.org/zh/sections/un-charter/chapter-,tolower(as.roman(1:19),/index.html)#其他页,下一行纠正不规范的第其他页,下一行纠正不规范的第17页页ch17=http:/www.un.org/zh/sections/un-charter/chapter-xvii-0/index.htmlch=c(preface,ch)#合并成合并成20个元素的网址向量个元素的网址向量Res=联合国
23、宪章联合国宪章n序言序言n#标题及换行标记标题及换行标记nfor(url in ch)h=read_html(url)#循环读入网址循环读入网址reps%html_node(.region-content)%#放入抓取的放入抓取的CSS代码代码html_text()#提取出文本提取出文本;结果的结果的reps是字符串是字符串reps=str_sub(reps,1,nchar(reps)-24)#去掉后面的不相关字符去掉后面的不相关字符Res=paste0(Res,n,reps)#把各个页的结果放到一起成为一个字符串把各个页的结果放到一起成为一个字符串cat(as.character(Res),
24、sep=“n”,file=“UNR.txt”,append=TRUE)#保保存存36四 网络爬虫的若干案例37例16.4.2:马克思恩格斯全集文章抓取 使用Python,文章的HTML 格式是表格形式,不使用BeautifulSoup,而使用另一个模块lxml:import requestsimport lxml.html as lhpage=requests.get(https:/www.marxists.org/chinese/marx-engels/01/011.htm)doc=lh.fromstring(page.content)#存入网络内容存入网络内容tr_ele=doc.xpat
25、h(/tr)#分析存在分析存在HTML元素的数据元素的数据text_file=open(Karl_Marx.txt,w)text_file.write(tr_ele0.text_content().replace(u30fb,)#把字符把字符tr_ele0包括格式存入文件包括格式存入文件.text_file.close()38例16.4.2:马克思恩格斯全集文章抓取 使用R,还是用程序包rvest 及SelectorGadget:library(rvest)library(tidyverse)library(stringr)url=https:/www.marxists.org/chinese
26、/marx-engels/01/011.htmh=read_html(url)reps%html_node(td)%html_text()cat(as.character(reps),sep=n,file=Karl.txt,append=TRUE)39例16.4.5:抓取微博账号“公安部儿童失踪信息紧急发布平台”儿童失踪信息 首先载入可能使用的模块:import requestsfrom lxml import etree微博爬取信息,首先需要自己微博账号的cookie,cookie 的获得方式为:在https:/ 中登入自己的微博账号,右键点击“检查”,“Network”中“Name”列表下
27、选择“”,点击右侧“Headers”,其中“Request Headers”下,“Cookie”后的值即为我们要找的cookie 值.40例16.4.5:抓取微博账号“公安部儿童失踪信息紧急发布平台”儿童失踪信息得到cookie 后,入该cookie 值(input 代码),由于该微博有多页,爬取多页的网站内容代码如下.若爬取页码较多,为防止IP 被封,可以使用代理IP,本文示例爬取前3 页:mycookie=input(input your cookie:)cookie=Cookie:mycookieurl=https:/ NT 10.0;Win64;x64;rv:57.0)Gecko/20
28、100101 Firefox/57.0,41例16.4.5:抓取微博账号“公安部儿童失踪信息紧急发布平台”儿童失踪信息with open(child.txt,w)as text_file:for i in range(1,4):if i=1:html=url+str(1)result=requests.get(html,cookies=cookie,headers=headers)selector=etree.HTML(result.content)contents=selector.xpath(/divclass=c)else:i=str(i)result=requests.get(html
29、,cookies=cookie,headers=headers)selector=etree.HTML(result.content)content=selector.xpath(/divclass=c)contents=contents+contenti=0for content in contents1:if content.xpath(./text()0=设置设置:or content.xpath(./text()0=彩版彩版|:continueelse:i=i+1news=content.xpath(./div1/spanclass=ctt/text()0.replace(u200b,
30、).replace(xa0,).replace(u202d,).replace(u202c,)print(i,news,file=text_file)42图16.6 cookie的获取方式例16.4.5:抓取微博账号“公安部儿童失踪信息紧急发布平台”儿童失踪信息43五 表格数据爬取44例16.5.1:财富杂志排行榜 对于表格数据的批量获取,有很多方便的软件,如excel中可以快速导出网页中的表格数据,又如商业软件八爪鱼13等,获取数据效率也非常高,这里仅用非商业开源软件作案例展示:首先,装入所需的模块:from bs4 import BeautifulSoupimport requestsim
31、port numpy as npimport pandas as pd输入网址,并利用request 和BeautifulSoup 模块的函数获得网页信息:45例16.5.1:财富杂志排行榜输入网址,并利用request 和BeautifulSoup 模块的函数获得网页信息:url=http:/ 浏览器的Inspect 功能找到表格位置,并提取:tt=soup.find_all(tbody)0.find_all(td)Res=for i in tt:Res.append(i.string)46例16.5.1:财富杂志排行榜把内容转换成数据框形式,并存入Fortune.csv 文件:R=np.array(Res).reshape(500,6)df=pd.DataFrame(R)df.columns=排名排名,上一年排名上一年排名,公司名称公司名称,营业收入营业收入,利润利润,国家国家df.head()图16.7:财富杂志排行榜前5(Python)47例16.5.1:财富杂志排行榜使用R:XML包url=http:/ 还是用R,只要成功抓取了一次,很快就会有很多次成功了.49谢谢敬请指正!