首页 > 代码库 > [Python] 网络爬虫实战(一):网站链接的初级爬取

[Python] 网络爬虫实战(一):网站链接的初级爬取

  闲来无事,想要学习一下Python,十月初的时候搭好了ubuntu的环境,用的是Ubuntu 16.04 32位+sublime Text3,轻量级的编程环境,感觉用起来还是比较舒服的。也陆陆续续地学习了一下python的语法和相关的知识点,并没有感觉到python有什么特别的地方,数据结构中的列表,元组和字典,还没有感到其特点在哪里比较明显,只是一个数据结构而已。恰好学院老师让搜集就业相关信息,所以就想尝试去先写一个爬虫,爬一下相关网站的相关链接。先提起兴趣,再去学习枯燥的知识点。

  一开始以为会是很大的工程量,周五下午回到宿舍就开始查相关资料,看了一下链接,先Mark一下:汪海的实验室,很多笔记,感觉应该专业人士,而且很巧也是山大毕业的。看到了一个比较简单的教程,利用审查元素和一个python的requests模块发送请求,然后利用pyquery模块来解析数据。当然,具体的jquery语法是什么样的我还是不清楚的=,=。教程中大体的思路就是在审查元素中,先定位自己想要爬取信息的位置,找到div的id,再找到具体的标签,然后就获取到了标题。当然获取的是一个列表数据,不仅仅可以找出标题,也可以提取出来链接。具体代码和效果如下图所示:

技术分享

技术分享

  当然,和教程还是有一点不一样的,教程中是先定位了模块的id,但是我们学校的就业信息网列表那里并没有模块的id,所以尝试直接取获取链接文本所在模块的信息。获取得到的内容除了我想要的东西意外还有奇奇怪怪的东西,后来查了一下模块的id是唯一的,但是模块下的子名字是可以重复的,因为获取的是列表,并且信息的格式基本上是固定的,所以直接获取列表的一个子表就可以了,当然=,=不懂html的我是不了解具体原因的。。

  这样就是静态的抓取了一个网页里面的部分文章标题及链接,但是想实现的是提醒更新的功能。很自然地一个想法就是拿爬下来的内容和之前的内容进行比较,没有更新的就直接忽略,有更新的话就把更新内容保存下来,最后只提醒更新内容就好了。正好python处理字符串还是比较人性化的,文件操作里面有f.readline(),同时可以直接进行字符串的比较,所以就拿爬下来的第一行数据和之前文件里的第一行数据进行比较,如果相同的话忽略本次爬取,不同的话循环比较,直到遇到相同的数据,把之前的数据存到本地,实现更新内容的动态提醒。最终实现了对三个网页,山东大学(威海)就业信息网的两个模块和哈尔滨工业大学(威海)的一个模块的数据提取。代码如下:

技术分享
  1 # coding = utf-8  2 # @ author  : blueprintf  3 # @ E-mail  : blueprintf@gmail.com  4 # @ version : 10/28  5 import requests  6 import sys  7 from pyquery import PyQuery as pq  8 reload(sys)  9 sys.setdefaultencoding(utf-8) 10  11 # output file init 12 fadd = /home/myc/Documents/pythonPro/update.txt 13 f = open(fadd, w+) 14 f.truncate() 15 f.close() 16  17 # sduwh campus recruitment 18 url = http://job.wh.sdu.edu.cn/item/79_1.html 19 r = requests.get(url) 20 p = pq(r.text).find(td>a) 21 length = len(p) 22 p = p[1:length - 6] 23 check = pq(p[0]).text() + \n 24 fadd = /home/myc/Documents/pythonPro/wh.txt 25 f = open(fadd, r+) 26 exist = f.readline() 27 f.close() 28 if exist != check: 29     print sduwh campus recruitment update 30     seq = ‘‘ 31     for d in p: 32         tmp = pq(d).text() + \n 33         if tmp == exist: 34             break 35         seq += pq(d).text() + \n + http://job.wh.sdu.edu.cn/ +  36             pq(d).attr(href) + \n 37  38     fadd = /home/myc/Documents/pythonPro/wh.txt 39     f = open(fadd, w) 40     f.write(seq) 41     f.close() 42     fadd = /home/myc/Documents/pythonPro/update.txt 43     f = open(fadd, a) 44     f.write(seq) 45     f.close() 46  47 # sduwh employ information 48 url = http://job.wh.sdu.edu.cn/item/80_1.html 49 r = requests.get(url) 50 p = pq(r.text).find(td>a) 51 length = len(p) 52 p = p[0:length - 6] 53 check = pq(p[0]).text() + \n 54 fadd = /home/myc/Documents/pythonPro/whzp.txt 55 f = open(fadd, r+) 56 exist = f.readline() 57 f.close() 58 if exist != check: 59     print sduwh employ information update 60     seq = ‘‘ 61     for d in p: 62         tmp = pq(d).text() + \n 63         if tmp == exist: 64             break 65         seq += pq(d).text() + \n + http://job.wh.sdu.edu.cn/ +  66             pq(d).attr(href) + \n 67     fadd = /home/myc/Documents/pythonPro/whzp.txt 68     f = open(fadd, w) 69     f.write(seq) 70     f.close() 71     fadd = /home/myc/Documents/pythonPro/update.txt 72     f = open(fadd, a) 73     f.write(seq) 74     f.close() 75  76 # hitwh employ information 77 url = http://job.hitwh.edu.cn/showmore.php?actiontype=5 78 r = requests.get(url) 79 r.encoding = gbk 80 p = pq(r.text).find(#p2_c td>a) 81 length = len(p) 82 p = p[3:length] 83 check = pq(p[0]).text() + \n 84 fadd = /home/myc/Documents/pythonPro/hitwh.txt 85 f = open(fadd, r+) 86 exist = f.readline() 87 f.close() 88 if exist != check: 89     print hitwh employ information update 90     seq = ‘‘ 91     for d in p: 92         tmp = pq(d).text() + \n 93         if tmp == exist: 94             break 95         seq += pq(d).text() + \n + http://job.hitwh.edu.cn/ +  96             pq(d).attr(href) + \n 97     fadd = /home/myc/Documents/pythonPro/hitwh.txt 98     f = open(fadd, w) 99     f.write(seq)100     f.close()101     fadd = /home/myc/Documents/pythonPro/update.txt102     f = open(fadd, a)103     f.write(seq)104     f.close()
View Code

  因为对python语言不太熟悉,所以可能很多语法的写法并不像python工程师的写法,之后会系统地学习然后改过。

  到这里还算比较顺利的,代码量不大,直接调库就实现了我想要的功能,一共用了三四个小时的样子,但是这样明显不能够满足我的需求,毕竟python是一个脚本文件,如果我想把它发给别人,那对方也必须要配置好python环境才可以运行。很自然的一个想法就是想把脚本文件转化成可执行文件(噩梦从此开始)。

  从网上查了一下,还真有实现这个功能的软件,也是一个脚本文件的样子,最常用的有两个:py2exe和pyinstaller,都是针对python2的。一开始尝试在ubuntu下进行文件转换,但是没有成功,猜想是因为在ubuntu下没有exe这样的文件格式(有成功在ubuntu下转换的欢迎交流)。然后在windows下因为我的电脑之前装的是python3.5,尝试卸载重新装2.7.x的时候环境可能出了点问题,不能实现pip功能,cmd下载速度也奇慢无比,遂借了舍友的电脑从安装python开始做起(若干个小时过去了)。。。。

  然后下载了py2exe和pyinstaller,分别进行了尝试。py2exe需要先自己写一个setup.py,写了个简单的但是报错缺少模块儿,尝试加失败,放弃。pyinstaller比较傻瓜,告诉他需要转成什么样的文件他就会帮你转,所以选择了这个。因为代码中用到了pyquery和requests两个包,所以就先下载这两个包,下载过程中pip报错,libxml2 not installed,下载了libxml2-python-2.7.7.win32-py2.7.exe,安装以后在Lib里面找到了libxml2,但是还是报错。。百度了好久也没有解决这个问题,有的说要先安装lxml,但是在安装高版本lxml的时候也会报这个错误。。所以就先安装了一个低版本的lxml,把pyquery包先装上了。

  然后尝试使用pyinstaller进行编译,编译很顺利,但是编译完之后直接闪退。查了很久,也查了pyinstaller相关的介绍说明,看见Build文件夹下面有一个warn*.txt文件,里面missing了各种模块,于是开始一个一个安装模块,但是并没有什么卵用,绝望=,=。快睡觉的时候才想起来自己的老本行,能不能debug一下,发现虽然还是会闪退,但是可以确定是在import pyquery的时候闪退的。这时候感觉lxml是肯定必须要升级的了,后来从网上找了一个lxml的安装文件,安装过程中没有报错,安装了以后竟然真的可以运行了,感动。

  但这个感动还是早了点,运行以后发现每次更新都会把所有数据全部输出一遍,而不是更新的那部分。后来才明白,windows下面和ubuntu下面的编码机制是不一样的。。OMG,给跪了,在ubuntu中,换行符是‘\n‘,而在windows下,换行符是‘\r\n‘,在编解码方面也有一定的差别,可以参考链接。一开始还想要print一下看看差别,后来一直在报解码错误,真的是蜜汁错误,用的utf-8编码,结果报GBK的错误。后来发现有repr函数可以直接显示编码的内容,干脆就直接比较编码了,发现windows的utf-8编码在开始的时候会有一个u‘\feff‘,猜可能是utf的编码标识符,所以用gbk去读的时候会错位读不出换行符?改完以后终于可以运行了,感动天感动滴。。

  还有一个点需要注意一下,在用pyinstaller进行转换的时候,可能会有关联文件,比如说调用了某个数据文件之类的,这个时候可以在生成的spec文件data那里就行修改,加上数据文件的路径。当然程序生成的文件是不需要加在里面的。

  最后。。两天时间做出来的程序的结果,这个必须要贴图了,还是比较满意的,之后可以加入其他的网页链接,继续丰富这个小程序。感觉爬虫做起来还是比较好玩的,但是工程性要强很多。

  技术分享

-------------------------------------------------我是分界线--------------------------------------------------

感想:

1,以前觉得python是个很高级的语言,会的人应该非常厉害,但是自己去做的时候才发现所谓高级语言是因为集成的好,只要会调用就可以实现想要的功能,难点反而是在于能不能把想法转化成简洁,高效的程序。

2,爬虫这种东西,真的是很可怕,可以大大提高人的工作效率,但也是个双刃剑,后来体会了一下爬虫爬去baidu搜索的相关信息,真的是和人肉搜索一样的感觉,所以在网上的信息尽量不要用真名和易于检索的资料。当然,那些大公司手里面的数据真的会很恐怖。

3,工程性的东西真的真的真的好繁琐!

[Python] 网络爬虫实战(一):网站链接的初级爬取