9用python写网络爬虫,完结
前言这是python网络爬虫的最后一篇给大家做个总结,且看且珍惜把!
截止到目前,前几章本书介绍的爬虫技术都应用于一个定制网站,这样可以帮助我们更加专注于学习特定技巧。而在本章中,我们将分析几个真实网站,来看看这些技巧是如何应用的。首先我们使用Google演示一个真实的搜索表单,然后是依赖JavaScript的网站Facebook,接下来是典型的在线商店Gap,最后是拥有地图接口的宝马官网由于这些都是活跃的网站,因此读者在阅读本书时这些网站存在已经发生变更的风险。不过这样也好,因为这些例子的目的是为了向你展示如何应用前面所学的技术,而不是展示如何抓取指定网站。当你选择运行某个示例时,首先需要检查网站结构在示例编写后是否发生过改变,以及当前该网站的条款与条件是否禁止了爬虫。9.1Google搜索引擎 根据第4篇文章中Alexa的数据,google.com是全世界最流行的网站之一,而且非常方便的是,该网站结构简单,易于抓取。 下图所示为Google搜索主页使用Firebug加载查看表单元素时的界面。 可以看到搜索查询存储在输入参数q当中,然后表单提交到action属性设定的search路径。我们可以通过将test作为搜索条件提交给表单对其进行测试,此时会跳转到类似https://www.google.com/search?q=test&oq=test&es_sm=93&ie=UTF-8的URL中。确切的URL取决于你的浏览器和地理位置。此外,还需要注意的是,如果开启了Google实时,那么搜索结果会使用AJAX执行动态加载,而不再需要提交表单。虽然URL中包含了很多参数,但是只有用于查询的参数q是必需的。当URL为https://www.google.com/search?q=test时也能产生相同的结果,如下图 所示。搜索结果的结构可以使用Firebug来检查,如下图所示。
从下图中可以看出,搜索结果是以链接的形式出现的,并且其父元素是class为”主”的<h3>标签。想要抓取搜索结果,我们可以使用第2篇文章中介绍的css选择器。
到目前为止,我们已经下载得到了Google的搜索结果,并且使用lxrnl抽取出其中的链接。在上图中,我们发现链接中的真实网站URL之后还包含了一串附加参数,这些参数将用于跟踪点击下面是第一个链接。
这里我们需要的内容是http://www.speedtest.net/,可以使用urlparse模块从查询字符串中其解析出来。
该查询字符串解析方法可以用于抽取所有链接。
成功了!从Google搜索中得到的链接已经被成功抓取出来了。该示例的完整源码可以从https://bitbucket.org/wswp/code/src/tip/chapter09/google.py获取。 抓取Google搜索结果时会碰到的一个难点是,如果你的IP出现可疑行为,比如下载速度过快,则会出现验证码图像如下图所示 我们可以使用第7章中介绍的技术来解决验证码图像这一问题,不过更好的方法是降低下载速度,或者在必须高速下载时使用代理,以避免被Google怀疑。9.2Facebook 目前,从月活用户数维度来看,Facebook是世界上最大的社交网络之一,因此其用户数据非常有价值。9.2.1网站 下图所示为Packt出版社的Facebook页面,其网址为https://www.facebook.com/PacktPub。 当你查看该页的源代码时,可以找到最开始的几篇日志,但是后面的日志只有在浏览器滚动时才会通过AJAX加载。另外,Facebook还提供了一个移动端界面,正如第l章所述,这种形式的界面通常更容易抓取。该页面在移动端的网址为https://m.facebook.com/PacktPub,如下图所示。 当我们与移动端网站进行交互,并使用Firebug查看时,会发现该界面使用了和之前相似的结构用于处理AJAX事件,因此该方法实际上无法简化抓取。虽然这些AJAX事件可以被逆向工程,但是不同类型的Facebook页面使用了不同的AJAX调用,而且依据我的过往经验,Facebook经常会变更这些调用的结构,所以抓取这些页面需要持续维护。因此,如第5章所述,除非性能十分重要,否则最好使用浏览器渲染引擎执行JavaScript事件,然后访问生成的HTML页面。 下面的代码片段使用Selenium自动化登录Facebook,并跳转到给定页面的URL。 然后,可以调用该函数加载你感兴趣的Facebook页面,并抓取生成的HTML页面。 9.2.2API 如第1章所述,抓取网站是在其数据没有给出结构化格式时的最末之选。而Facebook提供了一些数据的API,因此我们需要在抓取之前首先检查一下Facebook提供的这些访问是否己经满足需求。下面是使用Facebook的图形API从Packt出版社页面中抽取数据的代码示例。 该API调用以JSON格式返回数据,我们可以使用json模块将其解析为Python的diet类型。然后,我们可以从中抽取一些有用的特征,比如公司名、详细信息以及网站等。 图形API还提供了很多访问用户数据的其他调用,其文档可以从Facebook的开发者页面中获取网址为https://developers.facebook.com/docs/graph-api。不过,这些API调用多数是设计给与己授权的Facebook用户交互的Facebook应用的,因此在抽取他人数据时没有太大用途。要想得到更加详细的信息,比如用户日志,仍然需要爬虫。9.3Gap Gap拥有一个结构化良好的网站,通过Sitemap可以帮助网络爬虫定位其最新的内容。如果我们使用第1章中学到的技术调研该网站,则会发现在http://www.gap.com/robots.txt这一网址下的robots.txt文件中包含了网站地图的链接。下面是链接的Sitemap文件中的内容。
如上所示,Sitemap链接中的内容仅仅是索引,其中又包含了其他Sitemap文件的链接。其他的这些Sitemap文件中则包含了数千种产品类目的链接,比如http://www.gap.com/products/blue-long-sleeveshirts-for-men.jsp,如下图所示 这里有大量要爬取的内容因此我们将使用第4章中开发的多线程爬虫。你可能还记得该爬虫支持一个可选的回调参数,用于定义如何解析下载到的网页。下面是爬取Gap网站中Sitemap链接的回调函数。该回调函数首先检查下载到的URL的扩展名。如果扩展名为.xml,则认为下载到的URL是Sitemap文件,然后使用lxml的etree模块解析B任文件并从中抽取链接。否则,认为这是一个类目URL,不过本例中还没有实现抓取类目的功能。现在,我们可以在多线程爬虫中使用该回调函数来爬取gap.com了。
和预期一样,首先下载的是Sitemap文件,然后是服装类目。
9.4宝马 宝马官方网站中有一个查询本地经销商的搜索工具,其网址为https://www.bmw.de/de/home.html?entryType=dlo,界面如下图所示该工具将地理位置作为输入参数,然后在地图上显示附近的经销商地点比如在下图中以Berlin作为搜索参数
使用Firebug,我们会发现搜索触发了如下AJAX请求。
这里,maxResults参数被设为99。不过,我们可以使用第1章中介绍的技术增大该参数的值,以便在一次请求中下载所有经销商的地点。下面是将maxResults的值增加到1000时的输出结果
AJAX请求提供了JSONP格式的数据其中JSONP是指填充模式的JSON (JSONwithpadding)。这里的填充通常是指要调用的函数,而函数的参数则为纯JSON数据,在本例中调用的是callback函数。要想使用Python的json模块解析该数据,首先需要将填充部分截取掉。
现在,我们已经将德国所有的宝马经销商加载到JSON对象中,可以看出目前总共有731个经销商。下面是第一个经销商的数据。现在可以保存我们感兴趣的数据了。下面的代码片段将经销商的名称和经纬度写入一个电子表格当中。运行该示例后,得到的bmw.csv表格中的内容类似如下所示。 从宝马官网抓取数据的完整源代码可以从https://bitbucket.org/wswp/code/src/tip/chapter09/bmw.py获取。9.5本章小结 本章分析了几个著名网站,并演示了如何在其中应用本书中介绍过的技术。我们在抓取Google结果页时使用了css选择器,在抓取Facebook页面时测试了浏览器渲染引擎和API,在爬取Gap时使用了Sitemap,在从地图中抓取所有宝马经销商时利用了AJAX调用。
用Python写洛谷中的三道入门题
1.陶陶摘苹果
题目描述:
陶陶家的院子里有一棵苹果树,每到秋天树上就会结出 1010 个苹果。苹果成熟的时候,陶陶就会跑去摘苹果。陶陶有个 3030 厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳上再试试。
现在已知 1010 个苹果到地面的高度,以及陶陶把手伸直的时候能够达到的最大高度,请帮陶陶算一下她能够摘到的苹果的数目。假设她碰到苹果,苹果就会掉下来。
输入格式:
输入包括两行数据。第一行包含 1010 个 100100 到 200200 之间(包括 100100 和 200200 )的整数(以厘米为单位)分别表示 1010 个苹果到地面的高度,两个相邻的整数之间用一个空格隔开。第二行只包括一个 100100 到 120120 之间(包含 100100 和 120120 )的整数(以厘米为单位),表示陶陶把手伸直的时候能够达到的最大高度。
输出格式:
输出包括一行,这一行只包含一个整数,表示陶陶能够摘到的苹果的数目。
思路:
将第一行输入存入列表中,用变量h来记录陶陶把手伸直能够达到的最大高度。在for循环中进行比较是否能摘到,使用count记录能摘到的个数。
代码:
2.校门外的树
题目描述:
某校大门外长度为 l 的马路上有一排树,每两棵相邻的树之间的间隔都是 1 米。我们可以把马路看成一个数轴,马路的一端在数轴 0 的位置,另一端在 l 的位置;数轴上的每个整数点,即 0,1,2,…,l,都种有一棵树。
由于马路上有一些区域要用来建地铁。这些区域用它们在数轴上的起始点和终止点表示。已知任一区域的起始点和终止点的坐标都是整数,区域之间可能有重合的部分。现在要把这些区域中的树(包括区域端点处的两棵树)移走。你的任务是计算将这些树都移走后,马路上还有多少棵树。
输入格式:
第一行有两个整数,分别表示马路的长度 l 和区域的数目 m。
接下来 m 行,每行两个整数 u,v,表示一个区域的起始点和终止点的坐标。
输出格式:输出一行一个整数,表示将这些树都移走后,马路上剩余的树木数量。
思路:定义一个列表,定义列表的长度为了,列表里面的元素为0,通过for循环来将列表中长度在u和v之间的元素标记为1,最后遍历列表,用count来统计0的数量就是马路上剩余树的数量。
代码实现:
3.不高兴的津津
题目描述:
津津上初中了。妈妈认为津津应该更加用功学习,所以津津除了上学之外,还要参加妈妈为她报名的各科复习班。另外每周妈妈还会送她去学习朗诵、舞蹈和钢琴。但是津津如果一天上课超过八个小时就会不高兴,而且上得越久就会越不高兴。假设津津不会因为其它事不高兴,并且她的不高兴不会持续到第二天。请你帮忙检查一下津津下周的日程安排,看看下周她会不会不高兴;如果会的话,哪天最不高兴。
输入格式:
输入包括 7 行数据,分别表示周一到周日的日程安排。每行包括两个小于 10 的非负整数,用空格隔开,分别表示津津在学校上课的时间和妈妈安排她上课的时间。
输出格式:
一个数字。如果不会不高兴则输出 00,如果会则输出最不高兴的是周几(用 1,2,3,4,5,6,71,2,3,4,5,6,7 分别表示周一,周二,周三,周四,周五,周六,周日)。如果有两天或两天以上不高兴的程度相当,则输出时间最靠前的一天。
思路:
构建两个列表,一个列表的中的元素是1到7表示星期一到星期天,另一个列表用来存每天学习的时间。创建一个字典,其中的key为1-7,value为对应的学习时间。通过for循环来判断是否会生气。
代码实现;