ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ADS305 Big Data Lecuture4 Web Scraping

ADS305 Big Data Lecuture4 Web Scraping 本文为改编自shen 的一个笔记https://github.com/MushihimePepsi 主要是方便自己编辑文章目录1. 导入2. 网络服务器Web Servers3. 从APIs获取数据4. 使用Python进行数据抓取4.1 robots.txt4.2 教程步骤4.2.1 检查数据源4.2.2 从网页中抓取HTML内容4.2.3 解析从网页中抓取的HTML代码4.2.4 查找元素Find Elements4.2.4.1 通过ID查找HTML元素4.2.4.2 find()和findAll()4.2.4.3 通过HTML元素的类名来查找元素Find Elements by HTML Class Name4.2.4.3 find()函数的更多使用4.2.4.4 用树结构处理HTMLHTML Tree Structure4.2.4.5 从HTML元素中提取属性值Extract Attributes from HTML Elements5. 更多例子1. 导入就像前面导论所说数据挖掘Data Mining是一个跨学科领域受到多个不同学科的影响和贡献的。数据科学Data Science就是数据工程Data Engineering、数学与统计学Mathematics Statistics、实质性专业知识/商业智能这三个领域的结合。数据科学不仅需要技术能力来处理数据还需要数学和统计学知识来分析数据以及对特定领域的深入理解来解释数据并做出决策。我们这章就将深入数据爬取Web Scraping这一块的知识。术语补充Terminology Supplement网页抓取/网络爬取Web Scraping是**从网络中提取信息Extracting Information from the Web**的过程并且通常可以通过自动化Automation反复执行。一个典型流程可以概括为目标网站Target Website → 抓取Scraping → 结构化数据Structured Data即先确定目标网页再提取所需信息最后将结果保存为结构化格式Structured Format或数据库Database。2. 网络服务器Web Servers我们先回顾一遍网络服务器的相关知识。服务器是一个长时间运行的过程也称为守护进程它是一种软件程序它在计算机上运行并且可以持续运行很长时间。在网络环境中服务器通常被称为“守护进程”daemon因为它们在后台运行不需要用户直接交互。服务器会在计算机上监听一个特定的端口号。端口号Port Number是一个数字用于标识网络通信中的特定服务。例如HTTP超文本传输协议通常使用端口80而HTTPS安全的HTTP使用端口443。当客户端Client如网页浏览器 Browser向服务器发送请求时服务器会接收到这个请求Request并根据请求的内容生成相应的响应Response。这个响应可能包含网页内容、图片、视频等资源。客户端和服务器之间的通信通常使用HTTP协议。HTTP是一种应用层协议Application-layer Protocol用于在Web上传输超文本。它定义了客户端如何向服务器请求资源以及服务器如何将资源返回给客户端。当用户在浏览器中输入一个网址URL, Uniform Resource Locator统一资源定位符时浏览器会解析这个URL以确定需要访问的服务器地址和请求的资源路径。然后浏览器会构建一个HTTP请求并将其发送到服务器的指定端口。服务器接收到请求后会根据请求的资源路径找到相应的文件或执行相应的操作并将结果返回给浏览器。下图展示了用户通过浏览器访问网站并查看网页内容的流程。用户在浏览器中输入网址或点击链接。浏览器向网站服务器发送请求。网站服务器处理请求并将网页内容代码、图片、样式、数据等发送给浏览器。浏览器接收这些资源并将其解析为用户可以看到的图形界面。那数据抓取该怎么做呢这里不再是用户向网络服务器发送请求而是爬虫程序Scraper / Crawler / Spider向网站服务器发送请求请求获取网站上的数据。网站服务器响应请求将网页的代码、图片、样式、数据等资源发送给爬虫程序。爬虫程序解析Parse这些资源提取所需的数据。爬虫程序将提取的数据存储起来并可以对数据流进行监控以便在数据发生变化时进行相应的处理。这样就是一个数据爬取的完整流程。我们再看几个网络服务器的例子。先是本地网络服务器访问Jupyter Notebook通过下面的URL访问http://localhost:8888/Documents/cs109/BLA.ipynb#something其中协议protocolhttp表示使用超文本传输协议。主机名hostnamelocalhost表示本地计算机。端口port8888表示服务器监听的端口号。路径url/Documents/cs109/BLA.ipynb表示请求的资源路径。片段url fragment#something表示URL中的一个片段通常用于锚点定位。这里可以把 URL 的组成部分统一记为协议Protocol、主机名Hostname、端口Port、路径Path和片段Fragment。当用户在浏览器中输入上述URL并按下回车键时浏览器会向本地服务器发送一个HTTP请求。请求的格式如下Request: GET /request-URI HTTP/versionGET表示请求方法GET方法用于请求访问指定的资源。/request-URI请求的资源路径在这个例子中是/Documents/cs109/BLA.ipynb。HTTP/versionHTTP协议的版本例如HTTP/1.1。我们再看一个向Google发送请求并接受响应的例子。请求行Request Line请求行也可以理解为 HTTP 请求的第一行HTTP Request Line。GET / HTTP/1.0GETHTTP方法表示请求访问指定的资源。/请求的资源路径。在这个例子中请求的是Google的主页。HTTP/1.0HTTP协议的版本。请求头Request Headers请求头Headers用于携带关于客户端、目标主机、内容类型等附加信息。Host: www.google.comHost指定请求的目标主机名这里是www.google.com。响应部分Response状态行Status Line状态行HTTP Status Line通常包含 HTTP 版本、状态码Status Code和状态描述Reason Phrase。HTTP/1.0 200 OKHTTP/1.0HTTP协议的版本。200状态码表示请求成功。OK状态码的描述。响应头Response Headers响应头Response Headers描述服务器返回内容的元数据Metadata例如内容类型、缓存规则和 Cookie 等。Date: Mon, 14 Nov 2016 04:49:02 GMTExpires: -1Cache-Control: private, max-age0Content-Type: text/html; charsetISO-8859-1P3P: CP“This is …”Server: gwsX-XSS-Protection: 1; modeblockX-Frame-Options: SAMEORIGINSet-Cookie: NID90gb5q7b0…; expiresTue, 16-May-2017 04:49:02 GMT; path/; domain.google.com; HttpOnlyAccept-Ranges: noneVary: Accept-EncodingDate响应生成的日期和时间。Expires资源的过期时间-1表示立即过期。Cache-Control缓存控制指令private, max-age0表示不允许缓存。Content-Type响应内容的MIME类型这里是text/html字符集是ISO-8859-1。P3P隐私政策声明。Server服务器软件的信息。X-XSS-Protection跨站脚本XSS保护。X-Frame-Options防止点击劫持的选项。Set-Cookie设置一个Cookie用于会话管理。Accept-Ranges指示服务器是否支持范围请求。Vary指示代理服务器在缓存时需要考虑的请求头。响应体Response Body响应体Response Body / Message Body包含真正返回给客户端的资源内容例如 HTML 文档。!doctype htmlhtml itemscope“” itemtype“http://schema.org/WebPage” lang“en”headmeta contentSearch the world’s information,这是HTML文档的开始部分定义了文档类型、HTML元素及其属性如itemscope和itemtype并设置了语言为英语。我们再回顾一下HTTP状态码200 OK表示请求已成功处理服务器完成了客户端的请求并且一切正常。这是最常见的成功响应状态码。400 Bad Request表示客户端发送的请求存在语法错误服务器无法理解。这通常是由于请求格式不正确或包含无效的参数。401 Unauthorized表示客户端试图访问的资源需要授权但请求中未提供有效的授权信息。如果客户端提供了正确的授权凭证如用户名和密码可能会获得访问权限。403 Forbidden表示服务器理解了请求但是拒绝执行此请求。这通常是由于服务器配置问题或安全策略即使提供了授权信息也无法访问资源。404 Not Found表示服务器无法找到请求的资源。这通常意味着请求的URL不存在或者服务器上没有相应的文件或资源。也就是常说的“死链”。500 Internal Server Error表示服务器在处理请求时遇到了意外情况导致无法完成请求。这通常是服务器内部错误可能是代码错误、资源不足或其他问题。501 Not Implemented表示服务器不支持请求中使用的方法。例如客户端使用了服务器不支持的HTTP方法如PUT或DELETE。我们在本课程使用的工具是Python那我们如何使用Python来请求并获取网页内容呢我们可以使用Python的requests库Requests Library来完成。代码如下。importrequests reqrequests.get(https://en.wikipedia.org/wiki/Harvard_University)print(req)# 输出: Response [200]pagereq.text# 获取原始HTMLRaw HTMLprint(page[:500])# 打印前500个字符的HTML我们使用requests库发送请求。requests.get(“https://en.wikipedia.org/wiki/Harvard_University”)使用requests库中的get方法发送一个GET请求HTTP GET Request目标是哈佛大学的维基百科页面。然后print(req)打印响应对象Response Object显示状态码200表示请求成功。page req.text将响应的文本内容即网页的HTML代码存储在变量page中。然后print(page[:500])打印HTML内容的前500个字符以便快速查看网页的开头部分。3. 从APIs获取数据我们可以直接依靠API来获取数据。再回顾一下APIAPI Application Program Interface应用程序编程接口它是一组预定义的函数或协议允许不同的软件应用程序之间进行通信和数据交换。这里的 API 可以理解为软件之间约定好的“接口Interface”。常见的 HTTP 方法HTTP Methods包括 GET、POST、PUT、DELETE其中 GET 常用于检索Retrieve数据POST 常用于提交Submit数据。许多网站和服务如社交媒体、电子商务平台、地图服务等提供了API这些API主要用于网络与其他接口进行通信。API通常包含一组方法如GET、POST、PUT、DELETE等这些方法允许开发者搜索、检索或向数据源提交数据。这些方法定义了如何与API进行交互以及如何请求或修改数据。许多编程语言和框架提供了库或包这些库或包已经实现了与知名API的连接。这意味着开发者可以直接使用这些库来访问API而无需从头开始编写代码来处理API调用的所有细节。Any API的网站提供了一个平台开发者可以在这里找到、使用和测试大量公共API。这些API由不同的服务提供商提供涵盖了各种功能和服务。网址是 https://any-api.com。4. 使用Python进行数据抓取为什么要进行网页数据爬取呢主要原因是公司或网站没有提供官方的API来访问他们的数据。在这种情况下数据爬取可以作为一种替代方法来获取所需的信息。而且数据爬取可以自动化重复性的数据收集任务节省时间和劳动力。例如定期从多个网站收集价格信息或新闻更新。通过设置爬虫定期访问网站可以及时获取最新的数据和信息这对于需要实时或近实时数据的应用非常有用。对于许多开发者和数据爱好者来说数据爬取本身可以是一个有趣和有挑战性的活动。它结合了编程、数据分析和解决问题的技能可以带来满足感和乐趣。对于数据爬取我们需要注意以下几个问题确定要爬取的数据源和数据的相关性、时效性和可靠性。应对网站结构的不断变化这可能需要定期更新和维护爬虫。处理数据模式的变化确保爬取的数据仍然符合需求。课程补充Lecture Supplement正式开始抓取前还可以依次检查三个问题是否存在更容易的数据获取方式Easier Data Access例如原始数据集Raw Dataset、研究数据仓库Research Data Repository或官方 APIOfficial API。技术上是否可以抓取Technical Feasibility例如是否存在验证码CAPTCHA、请求频率限制Request Rate Limit或动态加载Dynamic Loading。法律和伦理上是否允许抓取Legal Ethical Feasibility需要检查使用条款Terms of Use、robots.txt、版权Copyright、隐私Privacy和数据共享政策Data Sharing Policy。**工具选择Tool Selection**可以按网页复杂度来判断简单静态网页Simple Static Webpage可以优先使用 Power Query 或 Google Sheets静态且页数较少、带分页Pagination的网页可使用 Web Scraper 浏览器插件Browser Plug-in动态网页Dynamic Webpage或大规模项目Large-scale Project通常需要编程Programming例如 Python、Selenium、Scrapy或者优先寻找官方 API。同时还要注意数据爬取时的法律和道德规范隐私Privacy隐私保护立法Privacy Legislation许多国家和地区都有法律保护个人信息的隐私。在进行数据爬取时必须遵守这些法律确保不侵犯个人隐私。为了遵守隐私法规通常建议只从公开可访问的来源爬取数据避免涉及个人隐私信息。网络礼仪Netiquette尊重机器人排除协议Robots Exclusion Protocol这是一种网站通过robots.txt文件来告诉爬虫哪些页面可以爬取哪些不可以。遵守这个协议是网络礼仪的一部分。robots.txt文件每个网站都有一个robots.txt文件列出了爬虫可以或不可以访问的页面。例如Disallow: /private/表示禁止爬虫访问/private/目录下的页面。在发送请求时通过User-Agent头部User-Agent Header标识自己的身份让网站知道是哪个爬虫在访问。为了避免对网站服务器造成过大负担建议在请求之间留出一些空闲时间避免频繁请求。选择在网站访问量较低的时段运行爬虫以减少对服务器的影响。如可行在开始爬取某个网站之前最好通知网站所有者并获得他们的许可以示尊重和透明度。在使用网络上的内容时必须注意版权问题Copyright Issues。未经版权所有者许可不得擅自使用受版权保护的材料。当使用或引用他人的工作时应适当地给予原作者或来源以信用这通常意味着要注明出处。了解并遵守与媒体相关的法律如版权法、隐私法、诽谤法等以确保你的网络活动合法。不要进行不道德的行为如发送垃圾邮件spam、过度请求导致网站过载等。4.1 robots.txtrobots.txt 是一个由网站所有者创建的文本文件它为网络爬虫包括自动化的数据爬取脚本提供了关于哪些页面可以被爬取哪些不可以的指令。在术语上robots.txt 属于机器人排除协议Robots Exclusion Protocol的一部分常见规则包括用户代理User-agent、允许Allow和禁止Disallow。它的作用是向网络爬虫Web Crawler / Bot声明访问规则。网站所有者或管理员负责创建和维护这个文件以控制爬虫对其网站的访问。这个文件包含了一系列的规则告诉爬虫哪些目录可以访问哪些应该被忽略。这些规则有助于防止爬虫访问敏感或不必要的页面。robots.txt 文件通常放置在网站的根目录下这样爬虫在访问网站时可以轻易地找到并读取它。例如访问 http://google.com/robots.txt 来查看 Google 网站的 robots.txt 文件。在进入 Python 教程前课程还介绍了一个无代码No-code流程使用 Web Scraper 浏览器插件时一般依次进行创建站点地图Create a Sitemap→ 添加选择器Add Selectors→ 预览数据Preview Data→ 开始抓取Scrape→ 刷新查看结果Refresh Results→ 导出数据Export DataCSV/XLSX。站点地图Sitemap描述抓取路径选择器Selector描述要提取的页面元素。4.2 教程步骤4.2.1 检查数据源我们可以打开一个网页并进行浏览甚至与网页交互我们需要熟悉目标网站的结构和内容了解数据的来源和组织方式为后续的数据爬取工作做好准备。例如我们访问这个网站https://realpython.github.io/fake-jobs/我们可以通过按下 F12 打开开发者工具Developer Tools来检查网页元素下面还列举了一些浏览器打开开发者工具的方式。Chrome/Edge浏览器可以通过按下 Ctrl Shift IWindows/Linux或 Cmd Option IMac来打开开发者工具。Safari浏览器可以通过按下 Cmd Option I 来打开开发者工具。我们打开元素“工具就可以检查、编辑和调试网页的HTML和CSS代码HTML CSS Code。将鼠标悬停在网页上的元素上开发者工具会高亮显示相应的HTML代码。点击该元素可以在开发者工具中查看和编辑其详细信息。HTML 结构补充HTML Structure SupplementHTMLHyperText Markup Language超文本标记语言可以看作一棵树Tree。常见标签Tags包括body、div、h1、p、a标签之间存在父元素Parent Element与子元素Child Element的层级关系Hierarchy。抓取时尤其常用属性Attributes例如class、id和href因为它们可以帮助我们更精确地定位目标元素Target Element。CSSCascading Style Sheets层叠样式表主要负责网页的样式Style而 HTML 主要负责网页的结构Structure。4.2.2 从网页中抓取HTML内容我们现在就可以使用Python的requests库进行数据抓取操作了。importrequests URLhttps://realpython.github.io/fake-jobs/pagerequests.get(URL)print(page.text)URL “https://realpython.github.io/fake-jobs/”定义要抓取的网页的URL。page requests.get(URL)使用requests.get()方法向指定的URL发送一个HTTP GET请求并将响应存储在变量page中。print(page.text)打印响应的文本内容即网页的HTML代码。这些都与前面的知识一致。这样我们就能从互联网上获取了静态网站内容Static Website Content。4.2.3 解析从网页中抓取的HTML代码我们已经获取了网页数据但是我们需要解析里面的HTML代码。importrequestsfrombs4importBeautifulSoup URLhttps://realpython.github.io/fake-jobs/pagerequests.get(URL)soupBeautifulSoup(page.content,html.parser)我们使用的是Beautiful Soup库Beautiful Soup Library这是用于解析HTML和XML文档HTML/XML Documents。soup BeautifulSoup(page.content, “html.parser”)使用Beautiful Soup解析从服务器返回的HTML内容。page.content包含响应的二进制内容html.parser指定使用Python的标准HTML解析器HTML Parser。这样做就方便我们后续的很多操作我们来一步步看。4.2.4 查找元素Find Elements当我们使用Beautiful Soup库解析HTML后我们就方便快捷地查找到我们想要的元素。4.2.4.1 通过ID查找HTML元素正在寻找的元素是一个具有ID属性值ID Attribute Value为ResultsContainer的div标签。这个div标签可能还有其他属性但主要关注的是它的ID。dividResultsContainer!-- all the job listings --/divBeautiful Soup允许我们通过元素的ID来查找特定的HTML元素。以下是相应的Python代码resultssoup.find(idResultsContainer)4.2.4.2 find()和findAll()findAll这个方法会返回文档中所有匹配的标签而不仅仅是第一个匹配的标签。它会将所有匹配的标签存储在一个列表中。这里的“所有匹配项”可以理解为匹配元素集合Collection of Matching Elements在 Beautiful Soup 中find_all()与findAll()都用于查找多个匹配元素。find这个方法只会返回文档中第一个匹配的标签。如果没有找到匹配的标签则返回None。下面的代码可以比较两者。importbs4## get bs4 objectsoupbs4.BeautifulSoup(source)## all a tagssoup.findAll(a)# 使用findAll获取所有a标签## first asoup.find(a)# 使用find获取第一个a标签## get all links in the pagelink_list[l.get(href)forlinsoup.findAll(a)]# 提取每个标签的href属性将结果存储在link_list中4.2.4.3 通过HTML元素的类名来查找元素Find Elements by HTML Class Name我们可以使用 .find_all() 方法查找所有具有特定类名的元素。例如这里每个工作职位的发布信息都被包裹在一个具有类名 card-content 的 div 元素中。job_elementsresults.find_all(div,class_card-content)这行代码使用 .find_all() 方法在 results 对象中查找所有div 元素这些元素具有类名 card-content。forjob_elementinjob_elements:print(job_element,end\n*2)我们使用这里的代码将每个工作职位的HTML元素打印出来而且每个元素之间有两行的间距。4.2.4.3 find()函数的更多使用我们可以进一步将这里的所需信息提取出来。forjob_elementinjob_elements:title_elementjob_element.find(h2,class_title)company_elementjob_element.find(h3,class_company)location_elementjob_element.find(p,class_location)print(title_element)print(company_element)print(location_element)print()对于每个 job_element使用 .find() 方法查找具有特定类名的元素title_element查找类名为 title 的 h2 元素。company_element查找类名为 company 的 h3 元素。location_element查找类名为 location 的 p 元素。这里的打印可以使用 .text 属性获取每个元素的文本内容Text Content并使用 .strip() 方法去除多余的空白字符。h2classtitle is-5Senior Python Developer/h2h3classsubtitle is-6 companyPayne, Roberts and Davis/h3pclasslocationStewartburg, AA/p我们已经知道页面中的职位标题被包含在 h2 元素中。为了筛选出特定的职位例如包含“Python”的职位可以使用 string 参数。python_jobsresults.find_all(h2,stringPython)这行代码使用 find_all 方法在 results 对象中查找所有包含文本“Python”的 h2 元素。我们也可以将函数传递给find_all方法以便根据特定条件查找HTML元素。如下所示。python_jobsresults.find_all(h2,stringlambdatext:pythonintext.lower())这里我们使用lambda函数检查每个元素的文本内容中是否包含“python”text.lower()保证了不区分大小写的搜索。能实现传递函数是因为string参数接受一个匿名函数lambda函数Anonymous/Lambda Function。4.2.4.4 用树结构处理HTMLHTML Tree StructureHTML文档的结构可以被视为一棵树其中每个标签都是一个节点。treebs4.BeautifulSoup(source)我们用这里的代码创建了一个Beautiful Soup对象tree它包含了解析后的HTML文档。source是HTML内容。root_nodetree.html这行代码获取HTML文档的根节点即html标签。bodyroot_node.contents[1]这行代码从根节点中获取第二个子节点即body标签。我们也可以直接访问标签。tree.body这行代码展示了另一种直接访问标签的方法。当然我们也可以访问HTML元素的父元素。python_jobsresults.find_all(h2,stringlambdatext:pythonintext.lower())python_job_elements[h2_element.parent.parentforh2_elementinpython_jobs]这段代码首先使用find_all方法查找所有包含文本“python”的h2元素并将结果存储在python_jobs列表中。然后使用列表推导式遍历python_jobs列表对于每个h2_element获取其父元素的父元素即曾祖父元素并将这些元素存储在python_job_elements列表中。补充理解连续两次.parent表示沿 DOM 树向上移动两层Move Up Two Levels in the DOM Tree实际对应哪一级容器要以当前 HTML 结构为准。4.2.4.5 从HTML元素中提取属性值Extract Attributes from HTML Elements现在我们要尝试从HTML中提取属性值。!-- snip --footerclasscard-footerahrefhttps://www.realpython.comtarget_blankclasscard-footer-itemLearn/aahrefhttps://realpython.github.io/fake-jobs/jobs/senior-python-devtarget_blankclasscard-footer-itemApply/a/footerdiv/div这个HTML示例展示了一个包含两个链接的footer元素每个链接都有一个href属性我们要提取这里的href属性href Attribute。代码如下。forjob_elementinpython_job_elements:# -- snip --linksjob_element.find_all(a)forlinkinlinks:link_urllink[href]print(fApply here:{link_url}\n)这段代码遍历python_job_elements列表其中包含所有包含“python”关键字的工作职位的HTML元素。对于每个job_element使用find_all方法查找所有a元素并将结果存储在links列表中。遍历links列表对于每个link元素使用link[“href”]提取其href属性值。打印出每个提取的链接URL。5. 更多例子下面这些工具分别对应自动化抓取Automated Scraping、爬虫框架Web Crawling Framework和自动化工作流Automated Workflow等进一步方向。自动化的网页数据抓取工具开源的网络爬虫框架Scrapy使用GitHub Actions的教程
返回列表