Python 爬虫学习笔记之多线程爬虫
XPath 的安装以及使用
1 . XPath 的介绍
刚学过正则表达式,用的正顺手,现在就把正则表达式替换掉,使用 XPath,有人表示这太坑爹了,早知道刚上来就学习 XPath 多省事 啊。其实我个人认为学习一下正则表达式是大有益处的,之所以换成 XPath ,我个人认为是因为它定位更准确,使用更加便捷。可能有的人对 XPath 和正则表达式的区别不太清楚,举个例子来说吧,用正则表达式提取我们的内容,就好比说一个人想去天安门,地址的描述是左边有一个圆形建筑,右边是一个方形建筑,你去找吧,而使用 XPath 的话,地址的描述就变成了天安门的具体地址。怎么样?相比之下,哪种方式效率更高,找的更准确呢?
2 . XPath 的安装
XPath 包含在 lxml 库中,那么我们到哪里去下载呢? 点击此处 ,进入网页后按住 ctrl+f 搜索 lxml ,然后进行下载,下载完毕之后将文件拓展名改为 .zip ,然后进行解压,将名为 lxml 的文件夹复制粘贴到 Python 的 Lib 目录下,这样就安装完毕了。
3 . XPath 的使用
为了方便演示,我利用 Html 写了个简单的网页,代码如下所示(为了节省时间,方便小伙伴们直接进行测试,可直接复制粘贴我的代码)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Test Html</title> </head> <body> <div id="content"> <ul id="like"> <li>like one</li> <li>like two</li> <li>like three</li> </ul> <ul id="hate"> <li>hate one</li> <li>hate two</li> <li>hate three</li> </ul> <div id="url"> <a href="http://www.baidu.com">百度一下</a> <a href="http://www.hao123.com">好123</a> </div> </div> </body></html>
用谷歌浏览器打开这个网页,然后右击,选择检查,会出现如下所示界面
这个时候你鼠标右击任何一行 html 代码,都可以看到一个 Copy,将鼠标放上去,就可以看到 Copy XPath ,先复制下来,怎么用呢?
# coding=utf-8 from lxml import etree f = open('myHtml.html','r') html = f.read() f.close() selector = etree.HTML(html) content = selector.xpath('//*[@id="like"]/li/text()') for each in content: print each
看看打印结果
like one like two like three
很显然,将我们想要的内容打印下来了,注意我们在 xpath() 中使用了 text() 函数,这个函数就是获取其中的内容,但是如果我们想获取一个属性,该怎么办?比如说我们想得到 html 中的两个链接地址,也就是 href 属性,我们可以这么操作
content = selector.xpath('//*[@id="url"]/a/@href') for each in content: print each
这个时候的打印结果就是
http://www.baidu.com http://www.hao123.com
看到现在大家大概也就对 xpath() 中的符号有了一定的了解,比如一开始的 // 指的就是根目录,而 / 就是父节点下的子节点,其他的 id 属性也是一步一步从上往下寻找的,由于这是一种树结构,所以也难怪方法的名字为 etree()。
4 . XPath 的特殊用法
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="likeone">like one</div> <div id="liketwo">like two</div> <div id="likethree">like three</div> </body> </html>
面对上面的一个网页,我们应该如何获取到三行的内容的 "like")]/text()')
不过这样有一点麻烦的地方,我们就需要手动的去写 XPath 路径了,当然也可以复制粘贴下来在进行修改,这就是提升复杂度来换取效率的问题了。再来看看标签嵌套标签的提取情况
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <div id="content"> <div id="text"> <p>hello <b> world <font color="#ffe4c4"> Python </font> </b> </p> </div> </div> </body> </html>
像上面这样的一个网页,如果我们想获取到 hello world Python 语句,该怎么获取呢?很明显这是一种标签嵌套标签的情况,我们按照正常情况进行提取,看看结果如何
content = selector.xpath('//*[@id="text"]/p/text()') for each in content: print each
运行之后,很遗憾的,只打印出了 hello 字样,其他字符丢失了,该怎么办呢?这种情况可以借助于 string(.)如下所示
content = selector.xpath('//*[@id="text"]/p')[0] info = content.xpath('string(.)') data = info.replace('\n','').replace(' ','') print data
这样就可以打印出正确内容了,至于第三行为什么存在,你可以将其去掉看看结果,到时候你自然就明白了。
Python 并行化的简单介绍
有人说 Python 中的并行化并不是真正的并行化,但是多线程还是能够显著提高我们代码的执行效率,为我们节省下来一大笔时间,下面我们就针对单线程和多线程进行时间上的比较。
# coding=utf-8 import requests from multiprocessing.dummy import Pool as ThreadPool import time def getsource(url): html = requests.get(url) if __name__ == '__main__': urls = [] for i in range(50, 500, 50): newpage = 'http://tieba.baidu.com/f"htmlcode">http://tieba.baidu.com/f"" src="/UploadFiles/2021-04-08/201609210933379.png">在当当网中搜索 Java ,出现了89页内容,我选择爬取了前 80 页,而且为了比较多线程和单线程的效率,我特意在这里对二者进行了比较,其中单线程爬取所用时间为 67s,而多线程仅为 15s 。
如何爬取网页,在上面 XPath 的使用中我们也已经做了介绍,无非就是进入网页,右击选择检查,查看网页 html 代码,然后寻找规律,进行信息的提取,在这里就不在多介绍,由于代码比较短,所以在这里直接上源代码。
# coding=utf8 import requests import re import time from lxml import etree from multiprocessing.dummy import Pool as ThreadPool import sys reload(sys) sys.setdefaultencoding('utf-8') def changepage(url, total): urls = [] nowpage = int(re.search('(\d+)', url, re.S).group(1)) for i in range(nowpage, total + 1): link = re.sub('page_index=(\d+)', 'page_index=%s' % i, url, re.S) urls.append(link) return urls def spider(url): html = requests.get(url) content = html.text selector = etree.HTML(content) title = [] title = selector.xpath('//*[@id="component_0__0__6612"]/li/a/@title') detail = [] detail = selector.xpath('//*[@id="component_0__0__6612"]/li/p[3]/span[1]/text()') saveinfo(title,detail) def saveinfo(title, detail): length1 = len(title) for i in range(0, length1 - 1): f.writelines(title[i] + '\n') f.writelines(detail[i] + '\n\n') if __name__ == '__main__': pool = ThreadPool(4) f = open('info.txt', 'a') url = 'http://search.dangdang.com/?key=Java&act=input&page_index=1' urls = changepage(url, 80) time1 = time.time() pool.map(spider, urls) pool.close() pool.join() f.close() print '爬取成功!' time2 = time.time() print '多线程耗时 : ' + str(time2 - time1) + 's' # time1 = time.time() # for each in urls: # spider(each) # time2 = time.time() # f.close() # print '单线程耗时 : ' + str(time2 - time1) + 's'可见,以上代码中的知识,我们都在介绍 XPath 和 并行化 中做了详细的介绍,所以阅读起来十分轻松。
好了,到今天为止,Python 爬虫相关系列的文章到此结束,谢谢你的观看。
下一篇:Python遍历目录并批量更换文件名和目录名的方法
人们对于笔记本电脑有一个固有印象:要么轻薄但性能一般,要么性能强劲但笨重臃肿。然而,今年荣耀新推出的MagicBook Pro 16刷新了人们的认知——发布会上,荣耀宣布猎人游戏本正式回归,称其继承了荣耀 HUNTER 基因,并自信地为其打出“轻薄本,更是游戏本”的口号。
众所周知,寻求轻薄本的用户普遍更看重便携性、外观造型、静谧性和打字办公等用机体验,而寻求游戏本的用户则普遍更看重硬件配置、性能释放等硬核指标。把两个看似难以相干的产品融合到一起,我们不禁对它产生了强烈的好奇:作为代表荣耀猎人游戏本的跨界新物种,它究竟做了哪些平衡以兼顾不同人群的各类需求呢?