【问题标题】:Web scraping using beautiful soup - how can I get all categories使用漂亮的汤进行网络抓取 - 我如何获得所有类别
【发布时间】:2019-07-26 03:27:47
【问题描述】:

我怎样才能获得同一网站“https://www.sfma.org.sg/member/category”的每个列表页面上提到的所有类别。例如,当我在上述页面上选择酒精饮料类别时,该页面上提到的列表具有这样的类别信息:-

Catergory: Alcoholic Beverage, Bottled Beverage, Spirit / Liquor / Hard Liquor, Wine, Distributor, Exporter, Importer, Supplier

我怎样才能用相同的变量提取这里提到的类别。

我为此编写的代码是:-

  category = soup_2.find_all('a', attrs ={'class' :'plink'})
  links = [links['href'] for links in category]

但它正在生成以下输出,这些输出是页面上的所有链接,而不是 href 中的文本:-

['http://www.sfma.org.sg/about/singapore-food-manufacturers-association',
 'http://www.sfma.org.sg/about/council-members',
 'http://www.sfma.org.sg/about/history-and-milestones',
 'http://www.sfma.org.sg/membership/',
 'http://www.sfma.org.sg/member/',
 'http://www.sfma.org.sg/member/alphabet/',
 'http://www.sfma.org.sg/member/category/',
 'http://www.sfma.org.sg/resources/sme-portal',
 'http://www.sfma.org.sg/resources/setting-up-food-establishments-in-singapore',
 'http://www.sfma.org.sg/resources/import-export-requirements-and-procedures',
 'http://www.sfma.org.sg/resources/labelling-guidelines',
 'http://www.sfma.org.sg/resources/wsq-continuing-education-modular-programmes',
 'http://www.sfma.org.sg/resources/holistic-industry-productivity-scorecard',
 'http://www.sfma.org.sg/resources/p-max',
 'http://www.sfma.org.sg/event/',
  .....]

如果问题似乎是新手,请原谅,我对python很陌生,

谢谢!!!

【问题讨论】:

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


    【解决方案1】:

    如果您只想要已经发布的结果中的链接,您可以这样获得:

    import requests 
    from bs4 import BeautifulSoup
    
    page = "https://www.sfma.org.sg/member/category/manufacturer"
    information = requests.get(page)
    soup = BeautifulSoup(information.content, 'html.parser')
    links = soup.find_all('a', attrs ={'class' :'plink'})
    for link in links:
        print(link['href'])
    

    输出:

    ../info/{{permalink}}
    http://www.sfma.org.sg/about/singapore-food-manufacturers-association
    http://www.sfma.org.sg/about/council-members
    http://www.sfma.org.sg/about/history-and-milestones
    http://www.sfma.org.sg/membership/
    http://www.sfma.org.sg/member/
    http://www.sfma.org.sg/member/alphabet/
    http://www.sfma.org.sg/member/category/
    http://www.sfma.org.sg/resources/sme-portal
    http://www.sfma.org.sg/resources/setting-up-food-establishments-in-singapore
    http://www.sfma.org.sg/resources/import-export-requirements-and-procedures
    http://www.sfma.org.sg/resources/labelling-guidelines
    http://www.sfma.org.sg/resources/wsq-continuing-education-modular-programmes
    http://www.sfma.org.sg/resources/holistic-industry-productivity-scorecard
    http://www.sfma.org.sg/resources/p-max
    http://www.sfma.org.sg/event/
    http://www.sfma.org.sg/news/
    http://www.fipa.com.sg/
    http://www.sfma.org.sg/stp
    http://www.sgfoodgifts.sg/
    

    但是,如果您想要网站上每个条目的链接,您需要将永久链接值与基本 url 连接起来。我已经从 nag 扩展了这个答案,以帮助从您正在查看的网站中获取您想要的数据。有一些固定链接值出现在第二个列表中,但不起作用(食品/饮料类型,而不是公司),所以我将它们删除。

    import requests
    from bs4 import BeautifulSoup
    from urllib.parse import urljoin
    import re
    
    
    page = "https://www.sfma.org.sg/member/category/manufacturer"
    information = requests.get(page)
    soup = BeautifulSoup(information.content, 'html.parser')
    
    url_list = []
    
    script_sections = soup.find_all('script')
    for i in range(len(script_sections)):
        if len(script_sections[i].contents) >= 1:
            txt = script_sections[i].contents[0]
            pattern = re.compile(r'permalink:\'(.*?)\'')
            permlinks = re.findall(pattern, txt)
            for i in permlinks:
                href = "../info/{{permalink}}"
                href = href.split('{')[0]+i
                full_url = urljoin(page, href)
                if full_url in url_list:
                    # drop the repeat extras?
                    url_list.remove(full_url)
                else:
                    url_list.append(full_url)
    
    for urls in url_list:
        print(urls)
    

    输出(截断):

    https://www.sfma.org.sg/member/info/1a-catering-pte-ltd
    https://www.sfma.org.sg/member/info/a-linkz-marketing-pte-ltd
    https://www.sfma.org.sg/member/info/aalst-chocolate-pte-ltd
    https://www.sfma.org.sg/member/info/abb-pte-ltd
    https://www.sfma.org.sg/member/info/ace-synergy-international-pte-ltd
    https://www.sfma.org.sg/member/info/acez-instruments-pte-ltd
    https://www.sfma.org.sg/member/info/acorn-investments-holding-pte-ltd
    https://www.sfma.org.sg/member/info/ad-wright-communications-pte-ltd
    https://www.sfma.org.sg/member/info/added-international-s-pte-ltd
    https://www.sfma.org.sg/member/info/advance-carton-pte-ltd
    https://www.sfma.org.sg/member/info/agroegg-pte-ltd
    https://www.sfma.org.sg/member/info/airverclean-pte-ltd
    ...
    

    【讨论】:

    • 非常感谢!!它确实帮助了我很多!
    【解决方案2】:

    您需要使用正则表达式从脚本中获取永久链接值并与基本 url 连接。这是示例

    import re
    from bs4 import BeautifulSoup
    from urllib.parse import urljoin
    
    base = 'https://www.sfma.org.sg/member/category/manufacturer'
    
    script_txt = """<script>
            var tmObject = {'tmember':[{id:'1',begin_with:'0-9',name:'1A Catering Pte Ltd',category:'22,99',mem_type:'1',permalink:'1a-catering-pte-ltd'},{id:'330',begin_with:'A',name:'A-Linkz Marketing Pte Ltd',category:'3,4,10,14,104,28,40,43,45,49,51,52,63,66,73,83,95,96',mem_type:'1',permalink:'a-linkz-marketing-pte-ltd'},{id:'318',begin_with:'A',name:'Aalst Chocolate Pte Ltd',category:'30,82,83,84,95,97',mem_type:'1',permalink:'aalst-chocolate-pte-ltd'},{id:'421',begin_with:'A',name:'ABB Pte Ltd',category:'86,127,90,92,97,100',mem_type:'3',permalink:'abb-pte-ltd'},{id:'2',begin_with:'A',name:'Ace Synergy International Pte Ltd',category:'104,27,31,59,83,86,95',mem_type:'1',permalink:'ace-synergy-international-pte-ltd'}
            </script>"""
    
    soup = BeautifulSoup(script_txt)
    
    txt = soup.script.get_text()
    pattern = re.compile(r'permalink:\'(.*?)\'}')
    
    permlinks = re.findall(pattern, txt)
    for i in permlinks:
        href = "../info/{{permalink}}"
        href = href.split('{')[0]+i
        print(urljoin(base, href))  
    
    https://www.sfma.org.sg/member/info/1a-catering-pte-ltd
    https://www.sfma.org.sg/member/info/a-linkz-marketing-pte-ltd
    https://www.sfma.org.sg/member/info/aalst-chocolate-pte-ltd
    https://www.sfma.org.sg/member/info/abb-pte-ltd
    https://www.sfma.org.sg/member/info/ace-synergy-international-pte-ltd
    

    【讨论】:

    • 我实际上是 python 新手,所以如果这似乎是一个愚蠢的问题,请原谅我,变量 script_txt 只包含部分脚本,而不是页面上的整个列表,我怎样才能得到完整脚本,以便我可以获取所有 URL,感谢您的帮助!
    • 需要从爬取的数据中提取脚本内容。你的全部内容都在变量soup 中。您可以使用soup.script.get_text() 获取脚本文本
    【解决方案3】:

    要获得制造商的正确总数 240(并获得所有类别或任何给定类别的总数):

    如果您只想要制造商列表,请先查看页面并检查应该有多少链接:

    通过确保 css 选择器具有父类 ul.w3-ul,我们在添加 .plink 的子类选择器时仅限于适当的链接。所以,我们在页面上有240 链接。


    如果我们只是在从requests 返回的 html 上使用它,我们会发现我们远远不够,因为许多链接是动态添加的,因此在不运行 javascript 的requests 中不存在。

    但是,所有链接(对于所有下拉选择 - 不仅仅是制造)都存在于 JavaScript 字典中,位于 script 标记内,我们可以看到下面的开头:


    我们可以使用以下表达式正则表达式输出这个对象:

    var tmObject = (.*?);
    


    现在,当我们检查返回的字符串时,我们可以看到我们有未加引号的键,如果我们希望使用 json 库读取这个字典,这可能会造成问题:

    我们可以使用hjson 库进行解析,因为这将允许不带引号的键。 * pip install hjson


    最后,我们知道我们拥有所有列表,而不仅仅是制造商;检查原始html中的标签,我们可以确定manufacturers标签与组代码97相关联。


    所以,我从 json 对象中提取链接和组作为元组列表。我在“,”上拆分了组,因此我可以使用 in 来过滤适当的制造代码:

    all_results = [(base + item['permalink'], item['category'].split(',')) for item in data['tmember']]
    manufacturers = [item[0] for item in all_results if '97' in item[1]]
    

    检查列表的最后一个 len 我们可以得到我们的目标240

    所以,我们有all_results(所有类别),一种按类别划分的方法,以及manufacturer 的工作示例。


    import requests
    from bs4 import BeautifulSoup as bs
    import hjson
    
    base = 'https://www.sfma.org.sg/member/info/'
    p = re.compile(r'var tmObject = (.*?);')
    r = requests.get('https://www.sfma.org.sg/member/category/manufacturer')
    data = hjson.loads(p.findall(r.text)[0])
    all_results = [(base + item['permalink'], item['category'].split(',')) for item in data['tmember']]  #manufacturer is category 97
    manufacturers = [item[0] for item in all_results if '97' in item[1]]
    print(manufacturers)
    

    【讨论】:

    • 非常感谢您提供如此详细的解释!是的,它确实给出了正确的数字,
    • 我想我已经成为这个hjson的粉丝了。
    【解决方案4】:

    您要查找的链接显然是由脚本填充的(在 Chrome->Inspect->Network 中查找https://www.sfma.org.sg/member/category/manufacturer 的响应)。如果您查看该页面,您将看到加载它的脚本。您将拥有列表,而不是抓取链接、抓取脚本。然后由于已知链接格式,插入来自 json 的值。瞧! 这是要使用的入门代码。你可以推断其余的。

    import requests 
    from bs4 import BeautifulSoup
    
    page = "https://www.sfma.org.sg/member/category/manufacturer"
    information = requests.get(page)
    soup = BeautifulSoup(information.content, 'html.parser')
    links = [soup.find_all('script')]
    

    【讨论】:

      猜你喜欢
      • 2021-08-11
      • 2022-01-08
      • 2022-01-20
      • 1970-01-01
      • 2020-05-02
      • 1970-01-01
      • 2021-07-14
      • 2020-08-14
      • 2018-10-19
      相关资源
      最近更新 更多