EasyTranslator 开发过程总结(二)

EasyTranslator 开发过程总结(二)

前言

上篇文章介绍的开发环境的准备,这篇文章将介绍各个翻译接口爬虫的实现方案。

所谓的爬虫就是用程序模拟浏览器访问网络服务器,获取数据并解析数据的过程。在爬虫的过程中有几点注意的地方:

  • 优先爬取移动版网页。原因是移动版文档结构比较简单,其次是有的网站的 PC 版有反爬虫策略,而移动版没有,例如后面将要讲到的 Google 翻译。
  • 优先获取 json 数据。有的网站提供了返回 json 数据的接口,如果发现网站有这样的接口,要优先向该接口发送请求,而不是直接获取 html 文档。
  • 解析文档提取数据时,首先要分析文档的结构,找出待提取数据周围的关键“特征”(标签、属性、内容),进而缩小范围,再利用文档节点的层次关系(父、子,兄弟等)进行定位。

1 定向爬虫的一般步骤

定向爬虫的一般步骤为:

Created with Raphaël 2.1.2 开始 明确爬虫的网站和任务 使用chrome开发者工具分析请求和响应信息 明确请求类型、URL、参数和数据。 利用程序发送请求 解析响应数据并提取关键信息 结束

2 爬取 Google 翻译

首先爬取 Google 翻译,下面就按照上面的步骤来。

使用 Google chrome 打开 Google 翻译的网页 (https://translate.google.cn/),下面我们就使用 chrome 的开发者工具看看,当我们在文本框中输入文本点击翻译按钮后,浏览器向服务器发送了那些请求,而服务器又作了那些响应。

在 chrome 中打开开发者工具 -> Network -> All,先 clear 一下,然后 F5 刷新以下,就可以看到如下界面。

这里写图片描述

可以看到,浏览器与服务器之间的交互信息,我们所关心的是 xhr 类型的信息。
这里写图片描述

点击某一条项目,左侧显示请求和响应的内容。利用 requests 爬虫时,就是根据这些请求的信息(URL、request headers、query string parameters 等)模拟浏览器发送 get 或 post 请求,从服务器获取数据。

点击 Response 的确看到服务器返回了 json 格式的翻译结果。

这里写图片描述

可是仔细看看 Headers 中的query string parameters ,发现有一个奇怪的 tk 值,这个 tk 值的计算较为复杂,由 js 计算出来的,是 google 翻译的反爬虫手段。tk 值不正确当然就无法从服务器得到翻译结果。于是,不得不寻找其它方案。

这里写图片描述

是否存在其它移动版或简版的 google 翻译网页呢?还真的有,我也是偶然间发现的(https://translate.google.cn/m)。不过这个接口不提供 json 数据格式,只提供 html 文档。

首先,应该利用 chrome 开发者工具的分析 html 文档,找出待提取数据的特征。

这里写图片描述

通过分析发现,翻译的结果隐藏在 一个div 标签中,并且带有属性 dir 和 class。那么不就可以利用 BeautifulSoup 的 find 方法进行定位了吗。完整代码如下:

def googleTraslator(text, flg=0):
    url = 'https://translate.google.cn/m'
    headers = {'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Mobile Safari/537.36'}
    params = {
        'hl': 'zh-CN',
        'sl': 'zh-CN',
        'tl': 'en',
        'ie': 'UTF-8',
        'q': text
    }
    if flg != 0:
        params['sl'] = 'en'
        params['tl'] = 'zh-CN'
    rs = requests.get(url, headers=headers, params=params, timeout=1)
    if rs.status_code != 200:
        print('请求错误代码: ', rs.status_code)
        return None
    soup = BeautifulSoup(rs.text.replace('\r\n', ''), 'lxml')
    return soup.find('div', {'dir': 'ltr', 'class': 't0'}).text

3 爬取百度翻译

爬取百度翻译的过程和上面爬取 Google 翻译的过程差不过,百度翻译 PC 版也有反爬虫策略,于是采用移动版的URL,模拟浏览器发送 post 请求,确实成功了,可是没几天就挂掉了!可能是百度翻译服务器升级了反爬虫策略,连移动版的也不可以了。

办法总是有的,百度为开发者提供了翻译开放平台,必须注册为开发者,并创建应用,获取 APP ID 和密钥才能调用该接口。接口的调用方法访问技术文档.

下面给出实现代码:

def baiduTranslator(text, flg=0):
    url = 'http://api.fanyi.baidu.com/api/trans/vip/translate'
    headers = {'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Mobile Safari/537.36'}
    appid = xxxxx
    secretKey = 'xxxxxx'
    salt =  random.randint(32768, 65536)
    t = str(appid) + text + str(salt) + secretKey
    sign = md5(t.encode('utf-8')).hexdigest()
    data = {
        'from': 'zh',
        'to': 'en',
        'q': text,
        'appid': 20180906000203440,
        'salt': salt,
        'sign': sign
    }
    if flg != 0:
        data['from'] = 'en'
        data['to'] = 'zh'
    rs = requests.post(url, headers=headers, data=data, timeout=1)
    if rs.status_code != 200:
        print('请求错误代码: ', rs.status_code)
        return None
    return rs.json()['trans_result'][0]['dst']

4 爬取金山词霸、必应翻译

这两个翻译网站比较“厚道”,没有严格的反爬虫策略,并且可以直接获取 json 数据,爬虫比较方便。

必应翻译:

def bingTranslator(text, flg=0):
    url = 'https://cn.bing.com/ttranslate'
    headers = {'user-agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36'}
    data = {
        'text': text,
        'from': 'zh-CHS',
        'to': 'en'
    }
    if flg != 0:
        data['from'] = 'en'
        data['to'] = 'zh-CHS'
    rs = requests.post(url, headers=headers, data=data, timeout=1)
    if rs.status_code != 200:
        print('请求错误代码: ', rs.status_code)
        return None
    return rs.json().get('translationResponse')

金山词霸翻译:

def jinshanTranslator(text, flg=0):
    url = 'http://fy.iciba.com/ajax.php'
    headers = {'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Mobile Safari/537.36'}
    params = {'a': 'fy'}
    data = {'f': 'zh', 't': 'en', 'w': text}
    if flg != 0:
        data['f'] = 'en'
        data['t'] = 'zh'
        if text[-1] != '.':
            data['w'] = text + '.'
    rs = requests.post(url, params=params, headers=headers, data=data, timeout=1)
    if rs.status_code != 200:
        print('请求错误代码: ', rs.status_code)
        return None
    return rs.json().get('content').get('out')

5 爬取有道翻译

有道翻译的爬取方法和 Google 翻译类似,也是基于 html 文档解析。既可以采用 BeautifulSoup 也可以直接采用正则表达式提取翻译文本。下面介绍正则表达式的方法。

首先还是要分析 html 文档,利用 chrome 查看源代码,定位并提取翻译结果所在的文档节点。

<ul id="translateResult"><li>摘要建立了一套基于模块化算法的道路交通流量测量系统,用于道路车辆的交通流量分析。整个道路交通流量测量系统由三个部分组成:图像预处理模块、车辆检测模块和流量统计模块。</li></ul>

则对应的正则表达是的 pattern 为:

patern = re.compile(r'<ul id="translateResult">.*?<li>(.*?)</li>.*?</ul>', re.S)

re.S 参数为的是让 * 也能匹配空白字符(换行符等)。

完整代码如下:

def youdaoTranslator(text, flg=0):
    url = 'http://m.youdao.com/translate'
    headers = {'User-Agent': 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Mobile Safari/537.36'}
    data = {
        'inputtext': text,
        'type': 'ZH_CN2EN'
    }
    if flg != 0:
        data['type'] = 'EN2ZH_CN'
    rs = requests.post(url, headers=headers, data=data, timeout=1)
    if rs.status_code != 200:
        print('请求错误代码: ', rs.status_code)
        return None
    patern = re.compile(r'<ul id="translateResult">.*?<li>(.*?)</li>.*?</ul>', re.S)
    m = re.search(patern, rs.text)
    return m[1]

6 爬取 CNKI 翻译助手

CNKI 翻译助手和以上的翻译有所不同,它主要用于翻译专业词汇,并不是用来翻译长文本的。如果非要翻译长文本可能得不到结果。

CNKI 的爬虫还是基于 html 文档解析。不过,要比前面的较为复杂,因为所要提取的数据在文档中比较分散,要仔细分析 html 的特点,在定位关键信息的时候基于运用了 两个主要的技巧:

  1. 化大为小,缩小范围
  2. 先抓明显特征,再纵向或横向导航。
def cnkiTranslator(text, flg=0):
    url = 'http://dict.cnki.net/dict_result.aspx'
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.119 Safari/537.36'}
    params = {'searchword': text}
    rs = requests.get(url, params=params, headers=headers, timeout=3)
    if rs.status_code != 200:
        print('请求错误代码: ', rs.status_code)
        return None
    # # print(rs.text)
    # e = etree.HTML(rs.text)
    # tables = e.xpath('//*[@id="lblresult"]/table[1]/tr/td[1]/table')
    # parseTable(tables)
    html = rs.text.replace('\r\n', '')
    soup = BeautifulSoup(html, 'lxml')
    tables = soup.select('table.main-table')
    # print(len(e))
    # print(e[0].text)
    if len(tables) == 0:
        print('没有查找到翻译结果!')
        return None
    result = []
    for table in tables:
        if table.img is not None and table.img.attrs['src'] == 'images/02.gif':
            d1 = dict()
            for t in table.select('font.text9'):
                l = []
                next_tr = t.parent.parent.next_sibling
                tts = next_tr.findAll('font', {'class': 'text6'})
                for tt in tts:
                    l.append(tt.text)
                d1[t.text] = l[:min(4, len(l))]
            # print(d1)
            result.append(d1)
        elif table.img is not None and table.img.attrs['src'] == 'images/word.jpg':
            t2s = table.findAll('table', {'id': re.compile(r'showjd_\d')})
            d2 = dict()
            for t2 in t2s:
                l = []
                text_zhs = t2.select('td.text11Green')
                for text_zh in text_zhs:
                    l.append(text_zh.parent.previous_sibling.text.strip())
                    l.append(text_zh.text.strip())
                key = t2.previous_sibling.select('a[href^="javascript:showjdsw"]')[0].text
                d2[key] = l[:min(4, len(l))]
            # print(d2)
            result.append(d2)
        if len(result) == 2:
            break
    return result

爬取过程主要使用了 find, findAll 和 select 函数。其中 find 返回第一个匹配的对象。findAll 和 select 都返回 list

find 与 findAll 的参数格式一样,例如

r = obj.find('tag_name', {'property_name1': value1, 'property_name2': value2, ...})

而且属性值可以是正则表达式。

而 select 是基于 CSS 选择器语法的,不支持正则表达式。CSS 语法参见 W3school CSS 选择器参考手册.

7 总结

以上介绍了不同翻译网站的爬虫实现,思路都是相同的,只是从服务器得到的数据形式不同,解析数据的方法也有所不同。

在爬虫的过程中学会使用 Google chrome 的开发者工具分析浏览器与服务器之间的来往信息,分析 html文档的结构等。使用的教程可以参考 chrome 调试工具常用功能整理.

猜你喜欢

转载自blog.csdn.net/healingwounds/article/details/82526042
今日推荐