如何使用单个脚本从具有不同源代码的不同站点中获取数据?

时间:2017-12-28 21:39:04

标签: python python-3.x web-scraping

我在python中编写了一个脚本来解析不同网站中可用的不同配置文件名称。每个链接都连接到其个人资料信息可用的每个人。在这一刻,我只想刮掉他们的个人资料名称。我在剧本中为三个不同的人提供了三个不同的链接。下面的脚本做得很好。我使用css选择器来从三个站点中删除配置文件信息。由于数量有限,我已经处理好了。但是,它可能有数百个链接。

现在,我的问题是:由于每个网站包含彼此非常不同的源代码,如何通过包含单独的{{1}除了我在此处所做的内容之外的单个脚本从这些网站中获取所有配置文件名称那些网站选择器是我知道的?如果链接数量为数百怎么办?

以下是我为了获取个人资料名称所写的内容(这里做得很好):

selectors

输出:

import requests 
from bs4 import BeautifulSoup

links = {
"https://www.paulweiss.com/professionals/associates/robert-j-agar",
"http://www.cadwalader.com/index.php?/professionals/matthew-lefkowitz",
"https://www.kirkland.com/sitecontent.cfm?contentID=220&itemID=12061"
}
for link in links:
    res = requests.get(link)
    soup = BeautifulSoup(res.text,"lxml")
    for item in soup.select("#leftnav,.article,.main-content-container"):
        pro_name = item.select(".page-hdr h1,b.hidepf,.bioBreadcrumb span")[0].text
        print(pro_name)

2 个答案:

答案 0 :(得分:2)

一般来说,如果可能的话,在任意站点上可靠地覆盖概要文件名称的所有可能的任意位置将是非常困难的。主要问题是您无法预测HTML布局在目标站点上的位置。

解决问题的一种可能的替代方法是从HTML解析切换到自然语言处理Named Entity Recognition in particular

可供选择的工具很少 - 来自nltk的{​​{3}},StanfordNERTagger等。

以下是使用nltk的示例(spacy应该有助于设置):

import nltk
import requests
from bs4 import BeautifulSoup

from nltk.tag.stanford import StanfordNERTagger


st = StanfordNERTagger('stanford-ner/english.all.3class.distsim.crf.ser.gz', 'stanford-ner/stanford-ner.jar')


links = {
    "https://www.paulweiss.com/professionals/associates/robert-j-agar",
    "http://www.cadwalader.com/index.php?/professionals/matthew-lefkowitz",
    "https://www.kirkland.com/sitecontent.cfm?contentID=220&itemID=12061"
}
for link in links:
    res = requests.get(link)
    soup = BeautifulSoup(res.text,"lxml")
    text = soup.body.get_text()

    for sent in nltk.sent_tokenize(text):
        tokens = nltk.tokenize.word_tokenize(sent)
        tags = st.tag(tokens)
        for tag in tags:
            if tag[1] == 'PERSON':
                print(tag)
    print("----------")

现在,这会提取人名,但也会产生很多噪音:

('Mark', 'PERSON')
('Adler', 'PERSON')
('Ellis', 'PERSON')
('Mark', 'PERSON')
('Adler', 'PERSON')
('J.D.', 'PERSON')
('Mark', 'PERSON')
('Adler', 'PERSON')
('Kirkland', 'PERSON')
('Mark', 'PERSON')
----------
('PAUL', 'PERSON')
('Agar', 'PERSON')
('Robert', 'PERSON')
...
('Paul', 'PERSON')
('Weiss', 'PERSON')
('Rifkind', 'PERSON')
----------
('Bono', 'PERSON')
('Bono', 'PERSON')
('ProjectsPro', 'PERSON')
...
('Jason', 'PERSON')
('Schwartz', 'PERSON')
('Jodi', 'PERSON')
('Avergun', 'PERSON')
('Top', 'PERSON')
----------

这种噪音的原因之一是我们正在解析网页body的文本,当然,其中包含大量无关信息。

整个命名实体识别问题非常有趣,还有很多其他技术,例如使用word2vec进行进一步分析:

深入学习的想法也在那里,仅举几例:

答案 1 :(得分:1)

您正在询问如何扩展以使用不同的HTML布局来抓取大量网站。

你已经有三个(link,pro_name)元组,以及三个相关CSS选择器的分离,以及从文本中提取pro_name的普通r'。*'正则表达式访问器。识别相关的选择器和正则表达式是缩放问题。您希望远离硬编码选择器,将它们放在某种数据存储区中。

所以你拥有的代码非常适合N = 3。这是您要编写的代码,用于处理任意N:“给定包含pro_name的HTML文档,选择器+访问器的哪个组合将可靠地提取该pro_name?”。要验证此类输出,您需要使用其他已知的pro_names来测试来自同一站点的一个或多个链接。就此而言,您需要验证重复访问相同链接会产生相同的结果,因为某些网站会在浏览器刷新时更改文档详细信息。

让selector_list成为CSS选择器,bs4将用于将DOM从根节点导航到叶节点。在你的问题中,你基本上发布了selector_list [-1],这是三个这样的列表的最终条目。

在训练时,首先输出selector_list,char_offset,word_offset和样板文件,其中可以从多个站点页面挖掘样板文本,并将其合并到正则表达式中。在发布的代码中,字符和单词的偏移量为“0”,表示空站点样板“”。然后,对于接受文本加上这四个参数的一些访问函数族,输出候选访问器(您的代码采用从字符偏移零开始的“接受r'。*'”),观察它们发出正确的pro_name。根据其他(document,pro_name)输入验证访问者。

在推理时,映射到访问者的链接,并使用它从生产中的HTML文档中提取pro_name。