Как скрести встроенные целые на сайте - PullRequest
1 голос
/ 21 июня 2019

Я пытаюсь определить количество лайков для наборов данных, доступных на этом веб-сайте.

Мне не удалось найти способ надежного определения и устранения взаимосвязи междузаголовок набора данных и тому подобное целое число:

enter image description here

, как это встроено в HTML, как показано ниже:

enter image description here

Ранее я использовал скребок для получения информации об URL ресурса.В этом случае мне удалось запечатлеть последнего потомка a родителя h3 с родителем, имеющим класс .dataset-item.

. Я хотел бы адаптировать свой существующий код, чтобы собрать количество лайков для каждогоресурс в каталоге, а не URL-адреса.Ниже приведен код скребка URL, который я использовал:

from bs4 import BeautifulSoup as bs
import requests
import csv
from urllib.parse import urlparse

json_api_links = []
data_sets = []

def get_links(s, url, css_selector):
    r = s.get(url)
    soup = bs(r.content, 'lxml')
    base = '{uri.scheme}://{uri.netloc}'.format(uri=urlparse(url))
    links = [base + item['href'] if item['href'][0] == '/' else item['href'] for item in soup.select(css_selector)]
    return links

results = []
#debug = []
with requests.Session() as s:

    for page in range(1,2):  #set number of pages

        links = get_links(s, 'https://data.nsw.gov.au/data/dataset?page={}'.format(page), '.dataset-item h3 a:last-child')

        for link in links:
            data = get_links(s, link, '[href*="/api/3/action/package_show?id="]')
            json_api_links.append(data)
            #debug.append((link, data))
    resources = list(set([item.replace('opendata','') for sublist in json_api_links for item in sublist])) #can just leave as set

    for link in resources:
        try:
            r = s.get(link).json()  #entire package info
            data_sets.append(r)
            title = r['result']['title'] #certain items

            if 'resources' in r['result']:
                urls = ' , '.join([item['url'] for item in r['result']['resources']])
            else:
                urls = 'N/A'
        except:
            title = 'N/A'
            urls = 'N/A'
        results.append((title, urls))

    with open('data.csv','w', newline='') as f:
        w = csv.writer(f)
        w.writerow(['Title','Resource Url'])
        for row in results:
            w.writerow(row)

Мой желаемый результат будет выглядеть так:

enter image description here

Ответы [ 2 ]

2 голосов
/ 21 июня 2019

Подход довольно прост. Ваш данный сайт содержит обязательные элементы в списке тегов. И что вам нужно сделать, это получить исходный код этого тега <li> и просто получить заголовок, у которого есть определенный класс, и То же самое относится к счетчику.

Подвох в том же количестве, что текст содержит некоторый шум. Чтобы это исправить, вы можете использовать регулярное выражение для извлечения цифр ('\ d +') из заданного ввода количества лайков. Следующий код дает желаемый результат:

from bs4 import BeautifulSoup as soup
import requests
import re
import pandas as pd

source = requests.get('https://data.nsw.gov.au/data/dataset')
sp = soup(source.text,'lxml')

element = sp.find_all('li',{'class':"dataset-item"})

heading = []
likeList = []
for i in element:
    try:
        header = i.find('a',{'class':"searchpartnership-url-analytics"})
        heading.append(header.text)
    except:
        header = i.find('a')
        heading.append(header.text)



    like = i.find('span',{'id':'likes-count'})
    likeList.append(re.findall('\d+',like.text)[0])




dict = {'Title': heading, 'Likes': likeList} 

df = pd.DataFrame(dict,index=False) 
print(df)

Надеюсь, это помогло!

1 голос
/ 21 июня 2019

Вы можете использовать следующее.

Я использую селектор css с синтаксисом Or для получения заголовка и лайков в виде одного списка (так как в каждой публикации есть оба). Затем я использую нарезку, чтобы отделить заголовки от лайков.

from bs4 import BeautifulSoup as bs
import requests
import csv

def get_titles_and_likes(s, url, css_selector):
    r = s.get(url)
    soup = bs(r.content, 'lxml')
    info = [item.text.strip() for item in soup.select(css_selector)]
    titles = info[::2]
    likes = info[1::2]
    return list(zip(titles,likes))

results = []

with requests.Session() as s:

    for page in range(1,10):  #set number of pages
        data = get_titles_and_likes(s, 'https://data.nsw.gov.au/data/dataset?page={}'.format(page), '.dataset-heading .searchpartnership-url-analytics, .dataset-heading [href*="/data/dataset"], .dataset-item  #likes-count')
        results.append(data)

results = [i for item in results for i in item]

with open(r'data.csv','w', newline='') as f:
        w = csv.writer(f)
        w.writerow(['Title','Likes'])
        for row in results:
            w.writerow(row)
...