Python之由公司名推算出公司官网(余弦相似度)_老胡的储物柜的博客-程序员宝宝

读大学时期写的博文

1.问题

对展会数据分类后,我的新任务是如何通过 公司名、公司地址、国家等海关数据推断出该公司的官网网站(若官网不存在则不考虑) 以下数据仅供参考:

公司名 国家 地址
JPW INDUSTRIES INC
427 NEW SANFORD RD LAVERGNE TN 37086 US
Fujian Xishi Co., Ltd CN, CHINA
BusinessPartner Co.,ltd

BENKAI Co.,Ltd

GOLD INC
18245 E 40TH AVE AURORA CO 80011 US

需要得到结果:

公司名 官方网站
JPW INDUSTRIES INC http://http://www.jpwindustries.com/
Fujian Xishi Co., Ltd http://www.xishigroup.com/
BusinessPartner Co.,ltd http://www.traderthailand.com/
BENKAI Co.,Ltd http://www.benkaico.com
GOLD INC https://goldbuginc.com/

2.解决

由数据可看出,公司名是绝对存在的,故解决思路是从公司名出发,而不怎么全面的国家以及地址信息则用来提高准确度。

大体思路是这样的,若公司官网存在,那么通过搜索引擎定会被检索到,搜索引擎自然首选 google,所以可以先通过获取谷歌搜索的结果,然后分析获取的结果,从而得出最可能是该公司网站的 url。 初步搜索一下,看看各种情况:

  • 第一种情况,检索即可很直观地得出结果

640?wx_fmt=jpeg

  • 第二种情况,检索不能直观地得出结果,但官网确实存在(第二检索个结果)

640?wx_fmt=jpeg

  • 第三种情况,输入公司名+公司地址和只输入公司名得出的结果不一样

640?wx_fmt=jpeg

对于第三种情况,可以看出输入公司名+公司地址得出的结果是绝对正确的。

观察第三种情况,当输入公司名+公司地址时,返回结果的右侧会出现公司的详细信息,经过验证,若出现这种情况,则其 website对应的 url绝对正确。

故代码的第一步骤可以首先检索公司名+公司地址,观察 website元素是否存在,若存在,返回公司官网,否则,对公司名进行检索,代码如下:

def searchWeb(query, tld='com', lang='en', tbs='0', num=10, safe='off', tpe='', user_agent=None):	
    query = quote_plus(query)	
    get_page(url_home % vars())	
    url = url_search_num % vars()	
    # Request the Google Search results page.	
    html = get_page(url)	
    try:	
        href = re.findall(r'Directions</a><a\s*class="fl"\s*href="(.*?)".*?>Website', str(html))[0]	
        link = filter_result(href)	
        return link	
    except:	
        pass	
    return None

640?wx_fmt=jpeg

能直接获取公司官网毕竟是少数,大多数据还是要通过一步步计算得出,主要经过以下步骤:

  • 获取搜索引擎检索结果提取url

  • 初步排除某些url

  • 余弦相似度计算最可能的结果

2.1.获取搜索引擎检索结果提取url

对于谷歌搜索,我使用了 MarioVilas的项目google,毕竟在国内,为了以防万一我也写了 yahoo搜索,代码如下:

#!/usr/bin/env	
# -*-coding:utf-8-*-	
# script: yahooSearch.py	
__author__ = 'howie'	
import sys	
import time	
if sys.version_info[0] > 2:	
    from urllib.request import Request, urlopen	
    from urllib.parse import quote_plus, urlparse	
else:	
    from urllib import quote_plus	
    from urllib2 import Request, urlopen	
    from urlparse import urlparse, parse_qs	
try:	
    from bs4 import BeautifulSoup	
    is_bs4 = True	
except ImportError:	
    from BeautifulSoup import BeautifulSoup	
    is_bs4 = False	
url_search = "https://search.yahoo.com/search?p=%(query)s&b=%(start)s&pz=%(num)s"	
headers = {	
    'accept-encoding': 'gzip, deflate, sdch, br',	
    'accept-language': 'zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4',	
    'upgrade-insecure-requests': '1',	
    'accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',	
    'cache-control': 'max-age=0',	
    'authority': ' search.yahoo.com'	
}	
# 默认user_agent	
user_agent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/52.0.2743.116 Safari/537.36'	
def filter_link(link):	
    try:	
        linkData = urlparse(link)	
        if linkData.netloc and "yahoo.com" not in linkData.netloc and "/search/srpcache" not in linkData.path:	
            return link	
    except Exception:	
        pass	
    return None	
def yahooSearch(query, start=0, num=10, page=1, pause=1.0):	
    """	
    获取雅虎搜索url	
    :param query: 搜索关键词	
    :param start: 开始条目,最好为0	
    :param num: 搜索条目 建议10的倍数	
    :param page: 页数	
    :param pause: 停顿时间	
    :return: 返回url	
    """	
    query = quote_plus(query)	
    while page > 0:	
        url = url_search % vars()	
        time.sleep(pause)	
        request = Request(url)	
        request.add_header('User-Agent', user_agent)	
        response = urlopen(request)	
        html = response.read()	
        if is_bs4:	
            soup = BeautifulSoup(html, 'html.parser')	
        else:	
            soup = BeautifulSoup(html)	
        anchors = soup.find(id="web").find_all('a')	
        for a in anchors:	
            try:	
                link = filter_link(a["href"])	
                if link:	
                    yield link	
            except KeyError:	
                continue	
        start += num + 1	
        page -= 1	
if __name__ == '__main__':	
    # GOLD INC 18245 E 40TH AVE AURORA CO 80011 US	
    for url in yahooSearch("GOLD INC 18245 E 40TH AVE AURORA CO 80011 US"):	
        print(url)

2.2.初步排除某些url

这个可根据个人需求来配置,可添加 webConfig.py脚本,排除某些 url:

# -*-coding:utf-8-*-	
__author__ = 'howie'	
config = dict(	
    # www开头或分割后数组大于二的网站	
    forbid_www=["www.linkedin.com", "www.alibaba.com"],	
    # 非www开头的网站	
    forbid=["imexbb.com", "made-in-china.com"]	
)

以公司名 BENKAICo.,Ltd为例,初步获取url: ['http://www.benkaico.com','http://hisupplier.com','http://www.hktdc.com/en']

2.3.余弦相似度计算最可能的结果

对于公司 BENKAICo.,Ltd,我们获得了三个结果,现在又该如何从该列表中取得最可能的结果呢。

这里可以采用余弦相似度,具体公式可google,稍稍解释下,对于这三个网站:

['http://www.benkaico.com', 'http://hisupplier.com', 'http://www.hktdc.com/en']```	
可以通过计算各个网站的`title`和`BENKAI Co.,Ltd`的相似程度来取得最可能的结果。	
#####2.3.1:对各网站title进行分词	
```python	
{'http://www.benkaico.com': ['benkai', 'co.', ',', 'ltd', '.'], 	
'http://www.hktdc.com/en': ['hktdc.com', 'â\x80\x93', 'page', 'not', 'found'], 	
'http://hisupplier.com': ['china', 'suppliers', ',', 'suppliers', 'directory', ',', 'china', 'manufacturers', 'directory', '-', 'hisupplier.com']}

2.3.2:构建单词向量

{'http://www.benkaico.com': [[0, 1, 1, 1, 1], [1, 1, 1, 1, 1]], 	
'http://www.hktdc.com/en': [[1, 1, 0, 0, 1, 0, 0, 0, 1], [0, 0, 1, 1, 0, 1, 1, 1, 0]],	
 'http://hisupplier.com': [[0, 0, 0, 1, 0, 0, 1, 1, 0, 1], [2, 1, 1, 0, 2, 1, 2, 0, 2, 0]]}

2.3.3:计算余弦相似度

{'http://www.benkaico.com': 0.94427190999915878, 	
'http://www.hktdc.com/en': 0.0, 	
'http://hisupplier.com': 0.31451985913875646}

通过比较,可以看到 http://www.benkaico.com相似度最高的结果,跟真实结果一样。

640?wx_fmt=jpeg

全部步骤代码如下:

# -*-coding:utf-8-*-	
__author__ = 'howie'	
from urllib import parse	
from bs4 import BeautifulSoup	
from collections import defaultdict	
import requests	
import re	
import nltk	
import time	
from config.webConfig import config	
from CosineSimilarity import CosineSimilarity	
from search.yahooSearch import yahooSearch	
from search.gooSearch import search, searchWeb	
class Website(object):	
    """	
    通过公司名等信息获取网站官网	
    """	
    def __init__(self, engine='google'):	
        self.forbid_www = config["forbid_www"]	
        self.forbid = config["forbid"]	
        self.engine = engine	
    def get_web(self, query, address=""):	
        """	
        获取域名	
        :param query: 搜索词	
        :param address: 在此加上地址时,query最好是公司名	
        :return: 返回最可能是官网的网站	
        """	
        if self.engine == 'google' and address:	
            allQuery = query + " " + address	
            result = searchWeb(query=allQuery, num=5)	
            if result:	
                return result	
        allDomain = self.get_domain(query)	
        if len(allDomain) == "1":	
            website = allDomain[0]	
        else:	
            # 初步判断网站域名	
            counts = self.get_counts(allDomain)	
            largest = max(zip(counts.values(), counts.keys()))	
            if largest[0] > len(allDomain) / 2:	
                website = largest[1]	
            else:	
                # 获取对应域名标题	
                domainData = self.get_title(set(allDomain))	
                # 计算相似度	
                initQuery = nltk.word_tokenize(query.lower(), language='english')	
                # 余弦相似性计算相似度	
                cos = CosineSimilarity(initQuery, domainData)	
                wordVector = cos.create_vector()	
                resultDic = cos.calculate(wordVector)	
                website = cos.get_website(resultDic)	
        return website	
    def get_domain(self, query):	
        """	
         获取谷歌搜索后的域名	
        :param query:搜索条件	
        :return:域名列表	
        """	
        allDomain = []	
        if self.engine == "google":	
            for url in search(query, num=5, stop=1):	
                allDomain += self.parse_url(url)	
        elif self.engine == "yahoo":	
            for url in yahooSearch(query):	
                allDomain += self.parse_url(url)	
        if not allDomain:	
            allDomain.append('')	
        return allDomain	
    def parse_url(self, url):	
        allDomain = []	
        domainParse = parse.urlparse(url)	
        # 英文网站获取	
        if "en" in domainParse[2].lower().split('/'):	
            domain = domainParse[1] + "/en"	
        else:	
            domain = domainParse[1]	
        domainList = domain.split('.')	
        # 排除干扰网站	
        if len(domainList) >= 3 and domainList[0] != "www":	
            isUrl = ".".join(domain.split('.')[-2:])	
            if isUrl not in self.forbid:	
                allDomain.append(domainParse[0] + "://" + isUrl)	
        elif domain not in self.forbid_www:	
            allDomain.append(domainParse[0] + "://" + domain)	
        return allDomain	
    def get_title(self, setDomain):	
        """	
        获取对应网站title,并进行分词	
        :param allDomain: 网站集合	
        :return: 网站:title分词结果	
        """	
        domainData = {}	
        for domain in setDomain:	
            headers = {	
                "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",	
                "Accept-Encoding": "gzip, deflate, sdch",	
                "Accept-Language": "zh-CN,zh;q=0.8,en-US;q=0.6,en;q=0.4",	
                "Cache-Control": "max-age=0",	
                "Proxy-Connection": "keep-alive",	
                "Upgrade-Insecure-Requests": "1",	
                "User-Agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.89 Safari/537.36",	
            }	
            try:	
                data = requests.get(domain, headers=headers).text	
                soup = BeautifulSoup(data, 'html.parser')	
                title = soup.title.get_text()	
                title = re.sub(r'\r\n', '', title.strip())	
                titleToken = nltk.word_tokenize(title.lower(), language='english')	
                domainData[domain] = titleToken	
            except:	
                pass	
        return domainData	
    def get_counts(self, allDomain):	
        """	
        返回网站列表各个域名数量	
        :param allDomain: 网站列表	
        :return: 网站:数量	
        """	
        counts = defaultdict(int)	
        for eachDomain in allDomain:	
            counts[eachDomain] += 1	
        return counts	
if __name__ == '__main__':	
    # allQuery = ["National Sales Company, Inc.", "Decor Music Inc.","Fujian Xishi Co., Ltd","Kiho USA Inc.","BusinessPartner Co.,ltd","BENKAI Co.,Ltd"]	
    # GOLD INC 18245 E 40TH AVE AURORA CO 80011 US	
    allQuery = ["ALZARKI INTERNATIONAL"]	
    website = Website(engine='google')	
    for query in allQuery:	
        time.sleep(2)	
        website = website.get_web(query=query)	
        print(website)

计算余弦相似度代码

# -*-coding:utf-8-*-	
# script: CosineSimilarity.py	
__author__ = 'howie'	
import numpy as np	
from functools import reduce	
from math import sqrt	
class CosineSimilarity(object):	
    """	
    余弦相似性计算相似度	
    """	
    def __init__(self, initQuery, domainData):	
        self.title = initQuery	
        self.data = domainData	
    def create_vector(self):	
        """	
        创建单词向量	
        :return: wordVector = {} 目标标题以及各个网站标题对应的单词向量	
        """	
        wordVector = {}	
        for web, value in self.data.items():	
            wordVector[web] = []	
            titleVector, valueVector = [], []	
            allWord = set(self.title + value)	
            for eachWord in allWord:	
                titleNum = self.title.count(eachWord)	
                valueNum = value.count(eachWord)	
                titleVector.append(titleNum)	
                valueVector.append(valueNum)	
            wordVector[web].append(titleVector)	
            wordVector[web].append(valueVector)	
        return wordVector	
    def calculate(self, wordVector):	
        """	
        计算余弦相似度	
        :param wordVector: wordVector = {} 目标标题以及各个网站标题对应的单词向量	
        :return: 返回各个网站相似度值	
        """	
        resultDic = {}	
        for web, value in wordVector.items():	
            valueArr = np.array(value)	
            # 余弦相似性	
            squares = []	
            numerator = reduce(lambda x, y: x + y, valueArr[0] * valueArr[1])	
            square_title, square_data = 0.0, 0.0	
            for num in range(len(valueArr[0])):	
                square_title += pow(valueArr[0][num], 2)	
                square_data += pow(valueArr[1][num], 2)	
            squares.append(sqrt(square_title))	
            squares.append(sqrt(square_data))	
            mul_of_squares = reduce(lambda x, y: x * y, squares)	
            resultDic[web] = numerator / sum_of_squares	
        return resultDic	
    def get_website(self, resultDic):	
        """	
        获取最可能是官网的网站	
        :param resultDic: 各个网站相似度值	
        :return: 最可能的网站 也可能为空	
        """	
        website = ''	
        largest = max(zip(resultDic.values(), resultDic.keys()))	
        if largest[0]:	
            website = largest[1]	
        # 当相似度为0	
        else:	
            websites = [key for key, values in resultDic.items() if values == 0.0]	
            for eachWebsite in websites:	
                keyword = ','.join(self.data[eachWebsite]).lower()	
                if 'home' in keyword or "welcome" in keyword:	
                    website = eachWebsite	
        return website

3.总结

至此,若有更好的解决方案,欢迎赐教,谢谢。

往期推荐:

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/source_code13/article/details/100919902

智能推荐

呕心整理Java中的12种常用设计模式以及应用场景_只为code醉的博客-程序员宝宝

策略模式:策略模式是一种行为型模式,它将对象和行为分开,将行为定义为 一个行为接口 和 具体行为的实现。策略模式最大的特点是行为的变化,行为之间可以相互替换。每个if判断都可以理解为就是一个策略,可以使得算法可独立于使用它的用户而变化。使用场景:1. 假设现在某超市有三个等级的会员,普通会员,VIP1,VIP2。2. 在结账的时候,三个登记的会员购买了同一种商品,普通会员不打折,VIP1打9折,VIP2打8折。

python语言哪个人创造_python语言是由哪个人创造的_weixin_39950812的博客-程序员宝宝

python语言是由哪个人创造的?5aH免费资源网Python 本义是指 “蟒蛇”,1989年荷兰人Guido van Rossum发明了一种面向对象的解释型高级编程语言,将其命名为Python,Python设计哲学为优雅、明确、简单,实际上Python始终贯穿着这一概念,以至于现在网络上流传着“人生苦短,我用Python”的说法。可见Python有着简单、开发速度快、节省实际和容易学习等特点。5...

socket多线程、一个服务器多客户端的实现_liyubao160的博客-程序员宝宝

鉴于ServerSocket的accept方法是阻塞的,那么只能通过多线程的方式实现多客户端连接与服务器连接基本步骤:1,服务端创建ServerSocket绑定端口号,循环调用accept()方法2,客户端创建一个socket并请求和服务器端连接3,服务器端接受客户端请求,创建socket与该客户建立连接4,两个socket在一个单独的线程上通话5,服务器端继续等待新的连接...

随便推点

SparkSql连接Hive的各种操作_郝少的博客-程序员宝宝

1、数据kv1.txt238val_23886val_86311val_31127val_27165val_165409val_409255val_255278val_278...2、代码测试package com.cn.sparkSqlimport java.io.Fileimport org.apache.spark.sql.{Row, SparkSes...

Unity与Android交互_烫青菜的博客-程序员宝宝

新建Android Studio项目;将Unity安装环境下Editor\Data\PlaybackEngines\AndroidPlayer\Variations\mono\Development\Classes的classes.jar放到AndroidStudio项目libs下;新建一个Library(在这种格式下才可以导出unity所需要的aar或jar文...

算法-合并 K 个升序链表_给定两个链表,每个链表都已经按升序排列,设计算法实现将两个链表合并到一个升序链_谈谈1974的博客-程序员宝宝

给定一个链表数组,每个链表都已经按升序排列,将所有链表合并到一个升序链表中,返回合并后的链表,输入:lists = [[1,4,5],[1,3,4],[2,6]]输出:[1,1,2,3,4,4,5,6]

SQL注入整形报错注入_整型注入类型不需要闭合字符_now ~ try的博客-程序员宝宝

1. 整形报错注入所谓整型报错注入,整型是注入点的数据类型,报错是信息的显示方式。1.1 整形PHP文件中关联MySQL的语句,Id为字符型,需要使用闭合字符。其中 $ id是以字符串的形式被解析的。闭合字符报错字符型注入。id=1 后面有单引号了,为字符型注入另一种PHP文件中关联MySQL的语句,Id为整型,不需要使用闭合字符。整形注入1.2 报错联合查询可以把我们想要的数据展示在网页上,替代网页上原有的数据内容,但要是没有显示怎么办?可以出现在报错中数据库返回到页面上

Sobel算子matlab实现 分类: 图像处理 2..._dengxundong1074的博客-程序员宝宝

算子实际上是用来对图像进行卷积处理,其本质是用变分法来处理梯度问题,用途就是边缘检测。45度和135度效果一般,水平检测加垂直检测效果还可以。function Sobel(name,Threshold) f = imread(name); f = rgb2gray(f); f = im2double(f); subplot(231);...

git add_「已注销」的博客-程序员宝宝

一、前言git add命令主要用于把我们要提交的文件的信息添加到索引库中。当我们使用git commit时,git将依据索引库中的内容来进行文件的提交。二、基本git add 表示 add to index only files created or modified and not those deleted 我通常是通过git add 的形式把我们添加到索引库中,可以是文件也可

推荐文章

热门文章

相关标签