Python 爬虫学习笔记之多线程爬虫


Posted in Python onSeptember 21, 2016

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>

用谷歌浏览器打开这个网页,然后右击,选择检查,会出现如下所示界面

Python 爬虫学习笔记之多线程爬虫

这个时候你鼠标右击任何一行 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>

面对上面的一个网页,我们应该如何获取到三行的内容的 ? 嗯哼,很简单,我写三个 XPath 语句不就好了,so easy 。 如果真是这样,那么我们的效率好像是太低了一点,仔细看看这三行 div 的 id 属性,好像前四个字母都是 like, 那就好办了,我们可以使用 starts-with 对这三行进行同时提取,如下所示

content = selector.xpath('//div[starts-with(@id,"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?kw=python&ie=utf-8&pn=' + str(i)
    urls.append(newpage)

  # 单线程计时
  time1 = time.time()
  for i in urls:
    print i
    getsource(i)
  time2 = time.time()

  print '单线程耗时 : ' + str(time2 - time1) + ' s'

  # 多线程计时
  pool = ThreadPool(4)
  time3 = time.time()
  results = pool.map(getsource, urls)
  pool.close()
  pool.join()
  time4 = time.time()
  print '多线程耗时 : ' + str(time4 - time3) + ' s'

打印结果为

http://tieba.baidu.com/f?kw=python&ie=utf-8&pn=50
http://tieba.baidu.com/f?kw=python&ie=utf-8&pn=100
http://tieba.baidu.com/f?kw=python&ie=utf-8&pn=150
http://tieba.baidu.com/f?kw=python&ie=utf-8&pn=200
http://tieba.baidu.com/f?kw=python&ie=utf-8&pn=250
http://tieba.baidu.com/f?kw=python&ie=utf-8&pn=300
http://tieba.baidu.com/f?kw=python&ie=utf-8&pn=350
http://tieba.baidu.com/f?kw=python&ie=utf-8&pn=400
http://tieba.baidu.com/f?kw=python&ie=utf-8&pn=450
单线程耗时 : 7.26399993896 s
多线程耗时 : 2.49799990654 s

至于以上链接为什么设置间隔为 50,是因为我发现在百度贴吧上没翻一页,pn 的值就会增加 50。 通过以上结果我们发现,多线程相比于单线程效率提升了太多太多。至于以上代码中多线程的使用,我就不再过多讲解,我相信只要接触过 Java 的人对多线程的使用不会陌生,其实都是大差不差。没有接触过 Java ?那就对不起了,以上代码请自行消化吧。

实战 -- 爬取当当网书籍信息

一直以来都在当当网购买书籍,既然学会了如何利用 Python 爬取信息,那么首先就来爬取一下当当网中的书籍信息吧。本实战完成之后的内容如下所示

Python 爬虫学习笔记之多线程爬虫

在当当网中搜索 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 相关文章推荐
Python 字符串定义
Sep 25 Python
python判断windows隐藏文件的方法
Mar 21 Python
python 读取excel文件生成sql文件实例详解
May 12 Python
Python实现文件信息进行合并实例代码
Jan 17 Python
对Python 除法负数取商的取整方式详解
Dec 12 Python
对python 读取线的shp文件实例详解
Dec 22 Python
pandas 选取行和列数据的方法详解
Aug 08 Python
pycharm创建scrapy项目教程及遇到的坑解析
Aug 15 Python
python爬虫模块URL管理器模块用法解析
Feb 03 Python
python selenium自动化测试框架搭建的方法步骤
Jun 14 Python
150行Python代码实现带界面的数独游戏
Apr 04 Python
如何使用Python自动生成报表并以邮件发送
Oct 15 Python
Python 爬虫学习笔记之单线程爬虫
Sep 21 #Python
Python 爬虫学习笔记之正则表达式
Sep 21 #Python
Python简单实现安全开关文件的两种方式
Sep 19 #Python
Python打包可执行文件的方法详解
Sep 19 #Python
Python实现拷贝多个文件到同一目录的方法
Sep 19 #Python
利用Python画ROC曲线和AUC值计算
Sep 19 #Python
Python文件与文件夹常见基本操作总结
Sep 19 #Python
You might like
Thinkphp5 如何隐藏入口文件index.php(URL重写)
2019/10/16 PHP
基于jquery的下拉框改变动态添加和删除表格实现代码
2020/09/12 Javascript
基于jquery的从一个页面跳转到另一个页面的指定位置的实现代码(带平滑移动的效果)
2011/05/24 Javascript
仿猪八戒网左下角的文字滚动效果
2011/10/28 Javascript
基于jquery的文章中所有图片width大小批量设置方法
2013/08/01 Javascript
js 获取经纬度的实现方法
2016/06/20 Javascript
Angularjs 制作购物车功能实例代码
2016/09/14 Javascript
真正好用的js验证上传文件大小的简单方法
2016/10/27 Javascript
bootstrap监听滚动实现头部跟随滚动
2016/11/08 Javascript
Windows系统下安装Node.js的步骤图文详解
2016/11/15 Javascript
Bootstrap弹出框modal上层的输入框不能获得焦点问题的解决方法
2016/12/13 Javascript
$.browser.msie 为空或不是对象问题的多种解决方法
2017/03/19 Javascript
JavaScript队列的应用实例详解【经典数据结构】
2017/04/12 Javascript
vue2+el-menu实现路由跳转及当前项的设置方法实例
2017/11/07 Javascript
ReactNative实现Toast的示例
2017/12/31 Javascript
浅谈Webpack打包优化技巧
2018/06/12 Javascript
教你如何用Node实现API的转发(某音乐)
2019/09/20 Javascript
Vue v-bind动态绑定class实例方法
2020/01/15 Javascript
vue学习笔记之作用域插槽实例分析
2020/02/01 Javascript
element el-tree组件的动态加载、新增、更新节点的实现
2020/02/27 Javascript
[00:34]DOTA2上海特级锦标赛 VG战队宣传片
2016/03/04 DOTA
Python下载懒人图库JavaScript特效
2015/05/28 Python
python爬虫之线程池和进程池功能与用法详解
2018/08/02 Python
python 字典中取值的两种方法小结
2018/08/02 Python
python图形开发GUI库wxpython使用方法详解
2020/02/14 Python
python中if及if-else如何使用
2020/06/02 Python
微信端html5页面调用分享接口示例
2018/03/14 HTML / CSS
HTML5基于flash实现播放RTMP协议视频的示例代码
2020/12/04 HTML / CSS
世界上最好的足球商店:Unisport
2019/03/02 全球购物
检察官就职演讲稿
2014/01/13 职场文书
党员干部2014全国两会学习心得体会
2014/03/10 职场文书
10的分与合教学反思
2014/04/30 职场文书
会计工作态度自我评价
2015/03/06 职场文书
2015年施工员工作总结范文
2015/04/20 职场文书
2016年学校禁毒宣传活动工作总结
2016/04/05 职场文书
pandas进行数据输入和输出的方法详解
2022/03/23 Python