故事是这样开始的
P:“我在把我们的破官网重新装修一下,我想问一下有没有办法一次性把同行的几十个展会介绍的内容全部弄下来呢”
P:“我手动的复制太慢了”
M:“有的”
正好有个场景可以感受下 python 的强大了,先来一段 slogan 镇楼
Life is short, you need Python -- Bruce Eckel
讲真,作为一个前端狗,本来是想用 node 写的,但是除开 js 语法,node 开发的知识基本上跟 python 一样,基本是空白的。日常除了用它写点,害,想了下没写啥,静态文件服务器用的 anywhere ,前端开发服务/代理用的 webpack 全家桶,所以还是 python 搞搞试试。
实践
首先,当然是要 google 搜索下啦。关键词“python 爬虫”, 工具-> 过去一年内。浏览第一页,得到几个关键词:Requests、lxml、BeautifulSoup、Xpath、Scrapy,然后再分别查了下这几个东西是干嘛的。随后,第一个抛弃的关键词就是Scrapy,因为虽然P说的这个几十个展会,其实主要就两个网站,就不大材小用了。
接着,对着网上的Python极简教程_Python爬取网站数据_非常详细的入门教程,写了个详情页的抓取,顿时觉得:X,这也太简单了吧!
继续摸索,处理翻页问题,处理写文件问题,以及学习了 python 的基础语法 w3school 大法好!下面就是当时实验的代码啦,不到20行,非常简单,顺便还对比了下BeautifulSoup和lxml.etree 的用法,当然最终选的是bs4,毕竟还是前端狗,css 选择器很情切,可以毫不夸张的说,前端狗最适合写爬虫了(手动狗头)
# coding=utf-8
import requests
from lxml import etree
from bs4 import BeautifulSoup
baseUrl = 'https://www.showguide.cn/'
fileObj = open('showguide.txt', 'w')
for x in range(1,2):
url_temp = "{}/zhbuilding/list_{}.html"
page = requests.get(url_temp.format(baseUrl, x))
dom = etree.HTML(page.content)
exh_list = dom.xpath('//p[@class="nr_tit"]//a')
# soup = BeautifulSoup(page.content, 'lxml')
# exh_list = soup.select('.nr_tit>a')
for each in exh_list:
print(each.text, ':', each.get("href"))
res_temp = '{} : {}{}'
fileObj.write(res_temp.format(each.text, baseUrl, each.get("href")))
fileObj.write('\n')
fileObj.close()
# ➜ py_spider python test.py
# 俄罗斯莫斯科国际地面、屋顶、墙面设计及技术展览会 : /zhanhui/flooring-show-moscow.html
# 阿曼马斯喀特国际建材展览会 : /zhanhui/thebigshow.html
# 加拿大多伦多国际石材展览会 : /zhanhui/stonexcanada.html
# 印尼雅加达国际陶瓷工业展览会 : /zhanhui/keramika.html
# 泰国曼谷国际建材及室内装饰展览会 : /zhanhui/architect.html
# 巴西圣保罗国际灯饰展览会 : /zhanhui/expolux.html
# 阿尔及利亚阿尔及尔国际建材及工程施工设备展览会 : /zhanhui/batimatec.html
有了以上一个 demo 的基础,最后通过对目标网站的一波分析,以及稍微一点点的抽象,构造了下数据结构,分成四大类,从装 python 3.0( mac 目前默认装的还是 2.7 ) 到最终打包压缩文件发给P,一起花了大概一下午的时间,用技术解决点实际问题,还是稍微有点点成就感的。下面再贴下其中一类代码
# coding=utf-8
import requests
import re
import os
from bs4 import BeautifulSoup
# 列表->获取链接->获取详细->保存
list_arr = [
{
'name': '签证办理',
'temp': 'http://www.eastyida.com/service/guide?stid=16&tpage={}',
'size': 5,
'select': '.qz-list>ul>li',
's_title': '.name',
's_href': 'a',
},
{
'name': '境外攻略',
'temp': 'http://www.eastyida.com/service/guide?stid=14&tpage={}',
'size': 2,
'select': '.news-list>ul>li',
's_title': '.tit',
's_href': 'a',
}
]
z_template = '''
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{}</title>
</head>
<body>
<h1>{}</h1>
<div>
{}
</div>
</body>
</html>
'''
path_z = './东方益达/'
for item in list_arr:
path_z_z = path_z + item['name']
if not os.path.exists(path_z_z):
os.makedirs(path_z_z)
for i in range(1, item['size']+1):
z_page = requests.get(item['temp'].format(i))
z_dom = BeautifulSoup(z_page.content, 'lxml')
z_list = z_dom.select(item['select'])
for z_each in z_list:
z_url = z_each.a['href']
z_name = z_each.select(item['s_title'])
if len(z_name) > 0:
z_name = z_name[0].text
z_name = re.sub("\/", "_", z_name)
# 获取并保存详细
z_path = '{}/{}.html'.format(path_z_z, z_name)
print(z_url, z_path)
try:
z_detail = requests.get(z_url)
z_d_dom = BeautifulSoup(z_detail.content, 'lxml')
z_ctn = z_d_dom.select('.news-content')[0]
z_file_obj = open(z_path, 'w')
z_file_obj.write(z_template.format(z_name, z_name, z_ctn))
z_file_obj.close()
except:
print("An exception occurred")
print(z_url, z_path)
总结
首先,作为一个前端狗非专业程序员深知这个案例是再简单不过,因为目标网站是纯静态的,无论是列表内容的渲染还是详情页 tab 的切换,都是后端渲染好的静态 HTML 返回的,大大降低了操作的难度。试想下如果目标站换成异步加载、SPA,tab 标签再来个异步组件什么的,反正脑子里大概过了下可能要用到Headless Browser了,比如著名的PhantomJS。下次有机会在倒腾下,复杂点场景的实践。
不过,通过这一个小小的忙也感受了一波 python 的强大以及便携,假如是要用 java 的话,估计配置个PATH ,JAVA_HOME估计都要半天了吧(不知道 java 方不方便干这事儿)。
EOF