关于最好大学排名的爬虫

来源:转载

概述

既然决定把视频上老师讲的实战都自己动手实现一遍,那么就先把最好大学排名这个实例自己写一遍。看视频的时候挺轻松的,但是到自己动手的时候才知道不容易,写这个程序遇到两个比较棘手的问题,一个是如何从网页中提取出自己想要的信息,另一个是信息以什么样的形式保存并展示出来。其实几乎所有的爬虫都会遇到这两个问题吧,希望在以后的练习中能不断增强对这两个问题的处理能力。当然,这个实例还有一个重要的作用是增强自己对beautifulsoup库的理解和运用。

准备工作

打开Chrome浏览器,查看要爬取的页面是否为静态页面,如果不是的话以目前的技术是不能对其进行爬取的,毕竟视频的录制已经有一段时间了,网页可能会有所变化。经检查,幸好网页还是静态的,就可以用requests+bs4对其进行爬取。

调试

不能抡起袖子,就在sublime中猛写代码,边写边改,其实效率是很低的,因为如果在编辑器中写代码调试,发现自己的代码不能抓取到目标信息,就必须修改代码并且重新对网页进行爬取操作,无疑这种人工的重复劳动是不行的,效率十分低下,毕竟只是个小白,不能一下子就把正确的信息抓取下来。
针对此问题,可以在Python shell中进行调试,这样就好了许多。在交互式窗口中引入requests和bs4,在shell中进行调试明显比在命令行中调试好了许多。
调试过程中尽量用浏览器的开发者工具对信息进行分析吧,如果用源代码对其进行分析的话,结构不清晰,不容易分析。

bd4的使用

根据个人的习惯,发现自己最常用的方法应该是find_all()、对子节点的访问和平行节点向下遍历了,有时还会遇到对标签的属性信息和文本信息的提取。

find_all()

标签对象的一个方法,主要是用来定位一个标签或者是一些标签的位置,返回的是一个列表,列表里的每个元素是一个tag对象。此方法常和标签的属性组合来完成定位,要注意的是,class属性由于和Python中的关键字冲突,所以用class_代替,由于此方法很常用,所以可以不写,直接加对括号就可以表示调用了此方法了,十分方便。

子节点遍历
  • "." 操作符 得到子节点中第一个符合的标签
  • .contents 返回一个含所有子节点的列表
  • .children 返回一个可迭代对象,内容和.contents是一样的
tbody.tr.td<td>1</td>

值得注意的是,空字符串或者是换行符也算是节点,这是一个大坑,要注意一点。

平行节点的向下遍历
  • .next_sibling 返回一个标签对象
  • .next_siblings 返回一个可迭代对象
对标签属性的访问
  • 类似于字典式的访问
  • get()
 tbody['class']['hidden_zhpm']tbody.get('class')['hidden_zhpm']

也许用第二种意思更清晰点吧==

对标签中文本信息的提取
  • .string
  • .text
  • .get_text()
td.string'1'td.text'1'td.get_text()'1'

遇到的问题

  1. 每所学校的标签基本上一样的,有些有属性还能精准定位,而有些没有属性,不能精准的定位,而且还有些空格或者是换行符还混进来,增加了提取信息的难度。
  2. 每所学校要获取的信息有三个:排名、学校名称和所在地区,应该以哪种方式对它们进行保存也是个问题。
  3. 把获取到的信息格式化输出也是个问题,因为要做到简洁、清晰和美观。
  • 对于第一个问题,既然有些标签没有属性,不能精确定位,又不能将其放弃,那么只能不用配合属性将它们都抓取下来,其中混杂着换行符这个垃圾信息,可以增加一个判断语句来将换行符给排除掉:
    if isinstance(tr, bs4.element.Tag)
  • 第二个问题,用列表的形式将这三个信息保存下来,而这三个元素是列表的一个元素,也就是嵌套列表,列表可以从主函数这边传递过去。
  • 第三个问题,格式化输出可以用字符串的format函数,但是还是遇到了问题,主要是大学名称太长会把后面的省市的一部分空间给占用掉,造成不对齐现象。测试了很多次,在设置的长度足够长的情况下,只要中文字数超过7个,必将不对齐,很神奇的现象,跑去论坛问,也没有谁说出个所以然来,很无奈。format函数在一般情况下不会出现问题,先这样吧。

总结

对于这个爬虫程序的编写,最大的收获就是帮助我理解和掌握beautifulsoup的用法,当然还有其他方面的收获,比如怎样将信息格式化输出和学习老师编写代码的方法,虽然最后格式化输出有点不理想,但整个程序在整体上还是成功的,希望自己继续努力。

源代码

from fake_useragent import UserAgentimport requestsfrom requests import Timeout, HTTPErrorfrom bs4 import BeautifulSoupimport bs4def get_page(url, ua): try: headers = {'User-Agent':ua} response = requests.get(url, headers=headers, timeout=10) response.raise_for_status() response.encoding = 'utf-8' return response.text except Timeout: print('requests timeout') get_page(url) except HTTPError: print('the http error(maybe status is not 200)') except: print('other error')def parse_page(html): soup = BeautifulSoup(html, 'html.parser') return soup def get_message(html, ulist): tbody = html.find('tbody', class_='hidden_zhpm') trs = tbody('tr') for tr in trs: if isinstance(tr, bs4.element.Tag): tds = tr.contents ulist.append([tds[2].string.strip(),tds[4].string.strip(), tds[0].string.strip()])def print_message(messages): templet = '{0:<50}/t{1:<50}/t{2:<50}' print(templet.format('排名', '学校名称', '省市')) for ult in messages: print(templet.format(ult[2], ult[0], ult[1], ' ')) def main(): ua = UserAgent() ua = ua.random url = 'http://www.zuihaodaxue.com/zuihaodaxuepaiming2016.html' html = get_page(url, ua) soup = parse_page(html) ulist = [] get_message(soup, ulist) print_message(ulist)main()

分享给朋友:
您可能感兴趣的文章:
随机阅读: