首页 > 解决方案 > 美丽的汤 find_all() 不返回所有元素

问题描述

我正在尝试使用 bs4抓取该网站。在特定的汽车广告图块上使用检查,我想出了我需要刮什么才能获得标题和汽车页面的链接。

我正在使用 bs4 库的 find_all() 函数,但问题是它没有抓取所有汽车的所需信息。它只返回大约 21 辆的信息,而在网站上可以清楚地看到大约有 2410 辆汽车。

相关代码:

from bs4 import BeautifulSoup as bs
from urllib.request import Request, urlopen 
import re
import requests

url = 'https://www.cardekho.com/used-cars+in+bangalore'
req = Request(url , headers={'User-Agent': 'Mozilla/5.0'})
webpage = urlopen(req).read()

page_soup = bs(webpage,"html.parser")

tags = page_soup.find_all("div","title")

print(len(tags))

如何获取页面上所有汽车的信息。

PS - 只想指出一件事,所有的汽车都不是一次显示的。向下滚动时会加载更多汽车信息。会不会是因为这个?没有把握。

标签: pythonpython-3.xweb-scrapingbeautifulsoup

解决方案


好的,我已经编写了一个示例代码来向您展示它是如何完成的。虽然该站点有一个我们可以利用的方便的 api,但第一页不能通过 api 获得,而是嵌入在代码中的script标签中html。这需要额外的处理来提取。之后,只需从 api 获取 json 数据,将其解析为 python 字典并将汽车条目附加到列表中。在滚动站点时检查 Chrome 或 Firefox 中的网络活动时,可以找到指向 api 的链接。

from bs4 import BeautifulSoup
import re
import json
from subprocess import check_output
import requests
import time
from tqdm import tqdm #tqdm is just to implement a progress bar, https://pypi.org/project/tqdm/

cars = [] #create empty list to which we will append the car dicts from the json data

url = 'https://www.cardekho.com/used-cars+in+bangalore'
r = requests.get(url , headers={'User-Agent': 'Mozilla/5.0'})
soup = BeautifulSoup(r.content.decode('utf-8'),"html.parser")
s = soup.find('script', {"type":"application/ld+json"}).next_sibling #find the section with the json data. It looks for a script tage with application/ld+json type, and takes the next tag, which is the one with the data we need, see page source code

js = 'window = {};\n'+s.text.strip()+';\nprocess.stdout.write(JSON.stringify(window.__INITIAL_STATE__));' #strip the text from unnecessary strings and load the json as python dict, taken from: https://stackoverflow.com/questions/54991571/extract-json-from-html-script-tag-with-beautifulsoup-in-python/54992015#54992015
with open('temp.js','w') as f: # save the sting to a javascript file
    f.write(js)

data_site = json.loads(check_output(['node','temp.js'])) #execute the file with node, which will return the json data that will be loaded with json.loads.
for i in data_site['items']: #iterate over the dict and append all cars to the empty list 'cars'
  cars.append(i)

for page in tqdm(range(20, data_site['total_count'], 20)): #'pagefrom' in the api call is 20, 40, 60, etc. so create a range and loop it
  r = requests.get(f"https://www.cardekho.com/api/v1/usedcar/search?&cityId=105&connectoid=&lang_code=en&regionId=0&searchstring=used-cars%2Bin%2Bbangalore&pagefrom={page}&sortby=updated_date&sortorder=asc&mink=0&maxk=200000&dealer_id=&regCityNames=&regStateNames=", headers={'User-Agent': 'Mozilla/5.0'})
  data = r.json()

  for i in data['data']['cars']: #iterate over the dict and append all cars to the empty list 'cars'
    cars.append(i)

  time.sleep(5) #wait a few seconds to avoid overloading the site

这将导致cars成为字典列表。车名可以在vid钥匙中找到,并且 url 存在于vlink钥匙中。您可以将其加载到 pandas 数据框中以探索数据:

import pandas as pd
df = pd.DataFrame(cars)

df.head()将输出(为了便于阅读,我省略了图像列):

位置 我的耳朵 BT 英尺 公里 圆周率 PN dvn 我知道了 尿酸 席位 ip OEM 模型 视频 城市 链接 p_numeric webp_image 位置 页号 中心变量 ID isExpiredModel 型号ID 是正版 is_ftc 卖家位置 utype 意见 tmGaadiStore 分类
0 科拉曼加拉 2014 越野车 柴油机 30,000 0 https://images10.gaadicdn.com/usedcar_image/320x240/used_car_2206305_1614944913.jpg 99 万 马恒达 XUV500 W6 2WD 13 3019084 9509A09F1673FE2566DF59EC54AAC05B 1 马恒达 马恒达 XUV500 马恒达 XUV500 2011-2015 W6 2WD 班加罗尔 /二手车详细信息/二手马恒达-XUV500-2011-2015-W6-2WD-cars-Bangalore_9509A09F1673FE2566DF59EC54AAC05B.htm 990000 https://images10.gaadicdn.com/usedcar_image/320x240webp/2021/used_car_2206305_1614944913.webp 1 1 3822 真的 570 0 0 {'address': 'BDA Complex, 100 Feet Rd, 3rd Block, Koramangala 3 Block, Koramangala, Bengaluru, Karnataka 560034, Bangalore', 'lat': 12.931, 'lng': 77.6228} 经销商 235 错误的
1 马拉哈利殖民地 2017 越野车 汽油 30,000 0 https://images10.gaadicdn.com/usedcar_image/320x240/used_car_2203506_1614754307.jpeg 78.5 万 福特 Ecosport 1.5 汽油趋势 BSIV 14 3015331 2C0E4C4E543D4792C1C3186B361F718B 1 福特 福特生态运动 福特 Ecosport 2015-2021 1.5 汽油趋势 BSIV 班加罗尔 /二手车详细信息/二手福特-Ecosport-2015-2021-1.5-Petrol-Trend-BSIV-cars-Bangalore_2C0E4C4E543D4792C1C3186B361F718B.htm 785000 https://images10.gaadicdn.com/usedcar_image/320x240webp/2021/used_car_2203506_1614754307.webp 2 1 6086 真的 175 0 0 {'address': '2, Varthur Rd, Ayyappa Layout, Chandra Layout, Marathahalli, Bengaluru, Karnataka 560037, Marathahalli Colony, Bangalore', 'lat': 12.956727624875453, 'lng': 77.70174980163576} 经销商 495 错误的
2 叶拉汉卡 2020 越野车 柴油机 13,969 0 https://images10.gaadicdn.com/usedcar_image/320x240/usedcar_11_276591614316705_1614316747.jpg 410万 丰田Fortuner 2.8 4WD AT 12 3007934 BBC13FB62DF6840097AA62DDEA05BB04 1 丰田 丰田财富 丰田 Fortuner 2016-2021 2.8 4WD AT 班加罗尔 /二手车详细信息/二手丰田-Fortuner-2016-2021-2.8-4WD-AT-cars-Bangalore_BBC13FB62DF6840097AA62DDEA05BB04.htm 4100000 https://images10.gaadicdn.com/usedcar_image/320x240webp/2021/usedcar_11_276591614316705_1614316747.webp 3 1 7618 真的 364 0 0 {'address': 'Sonnappanahalli Kempegowda Intl Airport Road Jala Uttarahalli Hobli, Yelahanka, Bangalore, Karnataka 560064', 'lat': 13.1518821, 'lng': 77.6220694} 经销商 516 错误的
3 比亚塔拉亚纳普拉 2017 轿车 柴油机 18,000 0 https://images10.gaadicdn.com/usedcar_image/320x240/used_car_2202297_1615013237.jpg 350万 梅赛德斯-奔驰 E 级 E250 CDI 前卫 15 3013606 4553943A967049D873712AFFA5F65A56 1 奔驰 奔驰E级 梅赛德斯-奔驰 E 级 2009-2012 E250 CDI 前卫 班加罗尔 /二手车详细信息/二手梅赛德斯-奔驰-E-Class-2009-2012-E250-CDI-Avantgarde-cars-Bangalore_4553943A967049D873712AFFA5F65A56.htm 350万 https://images10.gaadicdn.com/usedcar_image/320x240webp/2021/used_car_2202297_1615013237.webp 4 1 4611 真的 674 0 0 {'address': 'NO 19, Near Traffic Signal, Byatanarayanapura, International Airport Road, Byatarayanapura, Bangalore, Karnataka 560085', 'lat': 13.0669588, 'lng': 77.5928756} 经销商 414 错误的
4 2015 轿车 柴油机 80,000 0 https://stimg.cardekho.com/pwa/img/noimage.svg 125 万 斯柯达明锐 Elegance 2.0 TDI AT 1 3002709 156E5F2317C0A3A3BF8C03FFC35D404C 1 斯柯达 斯柯达明锐 斯柯达明锐 2013-2017 Elegance 2.0 TDI AT 班加罗尔 /二手车详细信息/二手Skoda-Octavia-2013-2017-Elegance-2.0-TDI-AT-cars-Bangalore_156E5F2317C0A3A3BF8C03FFC35D404C.htm 1250000 5 1 3092 真的 947 0 0 {'lat':0,'lng':0} 个人 332 错误的

或者,如果您希望将 dict 分解seller_location为列,则可以使用df = pd.json_normalize(cars).

您可以将所有数据保存到csv文件中:df.to_csv('output.csv')


推荐阅读