【问题标题】:Beautifulsoup "findAll()" does not return the tagsBeautifulsoup“findAll()”不返回标签
【发布时间】:2019-09-21 06:44:45
【问题描述】:

我正在尝试构建一个爬虫来获取一些学术论文的摘要及其相应的标题on this page

问题是我的for link in bsObj.findAll('a',{'class':'search-track'}) 没有返回我需要进一步构建刮板的链接。在我的代码中,检查是这样的:

for link in bsObj.findAll('a',{'class':'search-track'}):
     print(link)

上面的 for 循环确实会打印出任何内容,但是,href 链接应该在 <a class="search-track" ...</a> 内。

我提到了this post,但是更改 Beautifulsoup 解析器并不能解决我的代码问题。我在 Beautifulsoup 构造函数中使用"html.parser"bsObj = bs(html.content, features="html.parser")

print(len(bsObj)) 打印出“3”,同时为"lxml""html5lib" 打印出“2”。

另外,我开始使用urllib.request.urlopen 来获取页面,然后尝试使用requests.get()。不幸的是,这两种方法给了我相同的bsObj

这是我写的代码:

#from urllib.request import urlopen
import requests
from bs4 import BeautifulSoup as bs
import ssl


'''
The elsevier search is kind of a tree structure:
"keyword --> a list of journals (a journal contain many articles) --> lists of articles
'''
address = input("Please type in your keyword: ") #My keyword is catalyst for water splitting
#https://www.elsevier.com/en-xs/search-results? 
#query=catalyst%20for%20water%20splitting&labels=journals&page=1
address = address.replace(" ", "%20")
address = "https://www.elsevier.com/en-xs/search-results?query=" + address + "&labels=journals&page=1"

journals = []
articles = []

def getJournals(url):
    global journals

    #html = urlopen(url)
    html = requests.get(url)
    bsObj = bs(html.content, features="html.parser")

    #print(len(bsObj))
    #testFile = open('testFile.txt', 'wb')
    #testFile.write(bsObj.text.encode(encoding='utf-8', errors='strict') +'\n'.encode(encoding='utf-8', errors='strict'))
    #testFile.close()

    for link in bsObj.findAll('a',{'class':'search-track'}):
        print(link) 
        ########does not print anything########
        '''
        if 'href' in link.attrs and link.attrs['href'] not in journals:
            newJournal = link.attrs['href']
            journals.append(newJournal)
        '''
    return None


# Ignore SSL certificate errors
ctx = ssl.create_default_context()
ctx.check_hostname = False
ctx.verify_mode = ssl.CERT_NONE

getJournals(address)
print(journals)

谁能告诉我代码中for循环没有打印出任何链接的问题是什么?我需要将期刊的链接存储在一个列表中,然后访问每个链接以抓取论文摘要。按理说,论文的摘要部分是免费的,网站不应该因此屏蔽我的 ID。

【问题讨论】:

  • 你能简单地发布html = requests.get(url)使用的确切网址吗?
  • @JackFleeting 链接在这里:elsevier.com/en-xs/…

标签: python url web-scraping beautifulsoup python-requests


【解决方案1】:

这个页面是用jscript动态加载的,所以Beautifulsoup不能直接处理。您也许可以使用 Selenium 来实现,但在这种情况下,您可以通过跟踪页面进行的 api 调用来实现 (for more see, as one of many examples, here.

在您的特定情况下,可以这样做:

from bs4 import BeautifulSoup as bs
import requests
import json

#this is where the data is hiding:
url = "https://site-search-api.prod.ecommerce.elsevier.com/search?query=catalyst%20for%20water%20splitting&labels=journals&start=0&limit=10&lang=en-xs"
html = requests.get(url)
soup = bs(html.content, features="html.parser")


data = json.loads(str(soup))#response is in json format so we load it into a dictionary

注意:在这种情况下,也可以完全放弃 Beautifulsoup 并直接加载响应,如data = json.loads(html.content)。从此:

hits = data['hits']['hits']#target urls are hidden deep inside nested dictionaries and lists
for hit in hits:
    print(hit['_source']['url'])

输出:

https://www.journals.elsevier.com/water-research
https://www.journals.elsevier.com/water-research-x

等等

【讨论】:

  • 哦,非常感谢您的代码修复了它!但是由于这个 API 方法没有使用原始 URL 链接,而且这里显示的链接只返回第一页的结果,我怎样才能继续抓取搜索结果页面的第 2、第 3 页呢?很抱歉我对 API 操作不是很熟悉,但请问site-search-api.prod.ecommerce API 如何从网站获取信息,而不是使用 Elsevier 生成的 API 密钥?
  • 哦,我想我找到了解决问题的方法!通过增加&limit=0 中的数字,我抓取了更多的 URL。非常感谢您的启发!
  • @DanielQiao 很高兴它有帮助!是的,关于动态加载的页面还有很多东西要学……祝你好运。顺便说一句,如果你完成了,别忘了接受答案。