import requests # To download the html data from a site
from bs4 import BeautifulSoup # To parse the html data
import pandas as pd # To store our data in a DataFrame
Web scraping with Python
Load packages
Get the data
= "https://www.scrapethissite.com/pages/simple/"
url = requests.get(url) page
Explore the raw data
print(page.text[:70])
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
Parse the data
= BeautifulSoup(page.content, "html.parser") soup
Extract the relevant section of the html
= soup.find('div', attrs={'class' : 'col-md-4 country'})
test print(test.prettify())
<div class="col-md-4 country">
<h3 class="country-name">
<i class="flag-icon flag-icon-ad">
</i>
Andorra
</h3>
<div class="country-info">
<strong>
Capital:
</strong>
<span class="country-capital">
Andorra la Vella
</span>
<br/>
<strong>
Population:
</strong>
<span class="country-population">
84000
</span>
<br/>
<strong>
Area (km
<sup>
2
</sup>
):
</strong>
<span class="country-area">
468.0
</span>
<br/>
</div>
</div>
Extract information for one country
= test.find('h3', class_="country-name")
test_name = test.find('span', class_="country-capital")
test_cap = test.find('span', class_="country-population")
test_pop = test.find('span', class_="country-area") test_area
Let’s look at our test data:
print(test_name, test_cap, test_pop, test_area)
<h3 class="country-name">
<i class="flag-icon flag-icon-ad"></i>
Andorra
</h3> <span class="country-capital">Andorra la Vella</span> <span class="country-population">84000</span> <span class="country-area">468.0</span>
This is quite ugly …
Let’s remove the html formatting by extract only the text:
print(test_name.text, test_cap.text, test_pop.text, test_area.text)
Andorra
Andorra la Vella 84000 468.0
This is better, but let’s also remove all those spaces:
print(test_name.text.strip(), test_cap.text.strip(), test_pop.text.strip(), test_area.text.strip())
Andorra Andorra la Vella 84000 468.0
This is much more readable.
Extract information for all countries
Let’s create a set with the information for all countries:
= soup.find_all('div', class_="col-md-4 country") data
data
is a ResultSet object created by Beautiful Soup. It is an iterable, meaning that it can be used in a loop.
type(data)
bs4.element.ResultSet
For each element of data
(so for each country), we can now get our information:
for country in data[:5]:
= country.find('h3', class_="country-name")
name = country.find('span', class_="country-capital")
cap = country.find('span', class_="country-population")
pop = country.find('span', class_="country-area")
area print(name.text.strip(), cap.text.strip(), pop.text.strip(), area.text.strip())
Andorra Andorra la Vella 84000 468.0
United Arab Emirates Abu Dhabi 4975593 82880.0
Afghanistan Kabul 29121286 647500.0
Antigua and Barbuda St. John's 86754 443.0
Anguilla The Valley 13254 102.0
Store results in a DataFrame
Fist, we store the results in a list:
= []
ls
for country in data:
= country.find('h3', class_="country-name")
name = country.find('span', class_="country-capital")
cap = country.find('span', class_="country-population")
pop = country.find('span', class_="country-area")
area ls.append((name.text.strip(), cap.text.strip(), pop.text.strip(), area.text.strip()))
type(ls)
list
print(ls)
[('Andorra', 'Andorra la Vella', '84000', '468.0'), ('United Arab Emirates', 'Abu Dhabi', '4975593', '82880.0'), ('Afghanistan', 'Kabul', '29121286', '647500.0'), ('Antigua and Barbuda', "St. John's", '86754', '443.0'), ('Anguilla', 'The Valley', '13254', '102.0'), ('Albania', 'Tirana', '2986952', '28748.0'), ('Armenia', 'Yerevan', '2968000', '29800.0'), ('Angola', 'Luanda', '13068161', '1246700.0'), ('Antarctica', 'None', '0', '1.4E7'), ('Argentina', 'Buenos Aires', '41343201', '2766890.0'), ('American Samoa', 'Pago Pago', '57881', '199.0'), ('Austria', 'Vienna', '8205000', '83858.0'), ('Australia', 'Canberra', '21515754', '7686850.0'), ('Aruba', 'Oranjestad', '71566', '193.0'), ('Åland', 'Mariehamn', '26711', '1580.0'), ('Azerbaijan', 'Baku', '8303512', '86600.0'), ('Bosnia and Herzegovina', 'Sarajevo', '4590000', '51129.0'), ('Barbados', 'Bridgetown', '285653', '431.0'), ('Bangladesh', 'Dhaka', '156118464', '144000.0'), ('Belgium', 'Brussels', '10403000', '30510.0'), ('Burkina Faso', 'Ouagadougou', '16241811', '274200.0'), ('Bulgaria', 'Sofia', '7148785', '110910.0'), ('Bahrain', 'Manama', '738004', '665.0'), ('Burundi', 'Bujumbura', '9863117', '27830.0'), ('Benin', 'Porto-Novo', '9056010', '112620.0'), ('Saint Barthélemy', 'Gustavia', '8450', '21.0'), ('Bermuda', 'Hamilton', '65365', '53.0'), ('Brunei', 'Bandar Seri Begawan', '395027', '5770.0'), ('Bolivia', 'Sucre', '9947418', '1098580.0'), ('Bonaire', 'Kralendijk', '18012', '328.0'), ('Brazil', 'Brasília', '201103330', '8511965.0'), ('Bahamas', 'Nassau', '301790', '13940.0'), ('Bhutan', 'Thimphu', '699847', '47000.0'), ('Bouvet Island', 'None', '0', '49.0'), ('Botswana', 'Gaborone', '2029307', '600370.0'), ('Belarus', 'Minsk', '9685000', '207600.0'), ('Belize', 'Belmopan', '314522', '22966.0'), ('Canada', 'Ottawa', '33679000', '9984670.0'), ('Cocos [Keeling] Islands', 'West Island', '628', '14.0'), ('Democratic Republic of the Congo', 'Kinshasa', '70916439', '2345410.0'), ('Central African Republic', 'Bangui', '4844927', '622984.0'), ('Republic of the Congo', 'Brazzaville', '3039126', '342000.0'), ('Switzerland', 'Bern', '7581000', '41290.0'), ('Ivory Coast', 'Yamoussoukro', '21058798', '322460.0'), ('Cook Islands', 'Avarua', '21388', '240.0'), ('Chile', 'Santiago', '16746491', '756950.0'), ('Cameroon', 'Yaoundé', '19294149', '475440.0'), ('China', 'Beijing', '1330044000', '9596960.0'), ('Colombia', 'Bogotá', '47790000', '1138910.0'), ('Costa Rica', 'San José', '4516220', '51100.0'), ('Cuba', 'Havana', '11423000', '110860.0'), ('Cape Verde', 'Praia', '508659', '4033.0'), ('Curacao', 'Willemstad', '141766', '444.0'), ('Christmas Island', 'Flying Fish Cove', '1500', '135.0'), ('Cyprus', 'Nicosia', '1102677', '9250.0'), ('Czech Republic', 'Prague', '10476000', '78866.0'), ('Germany', 'Berlin', '81802257', '357021.0'), ('Djibouti', 'Djibouti', '740528', '23000.0'), ('Denmark', 'Copenhagen', '5484000', '43094.0'), ('Dominica', 'Roseau', '72813', '754.0'), ('Dominican Republic', 'Santo Domingo', '9823821', '48730.0'), ('Algeria', 'Algiers', '34586184', '2381740.0'), ('Ecuador', 'Quito', '14790608', '283560.0'), ('Estonia', 'Tallinn', '1291170', '45226.0'), ('Egypt', 'Cairo', '80471869', '1001450.0'), ('Western Sahara', 'Laâyoune / El Aaiún', '273008', '266000.0'), ('Eritrea', 'Asmara', '5792984', '121320.0'), ('Spain', 'Madrid', '46505963', '504782.0'), ('Ethiopia', 'Addis Ababa', '88013491', '1127127.0'), ('Finland', 'Helsinki', '5244000', '337030.0'), ('Fiji', 'Suva', '875983', '18270.0'), ('Falkland Islands', 'Stanley', '2638', '12173.0'), ('Micronesia', 'Palikir', '107708', '702.0'), ('Faroe Islands', 'Tórshavn', '48228', '1399.0'), ('France', 'Paris', '64768389', '547030.0'), ('Gabon', 'Libreville', '1545255', '267667.0'), ('United Kingdom', 'London', '62348447', '244820.0'), ('Grenada', "St. George's", '107818', '344.0'), ('Georgia', 'Tbilisi', '4630000', '69700.0'), ('French Guiana', 'Cayenne', '195506', '91000.0'), ('Guernsey', 'St Peter Port', '65228', '78.0'), ('Ghana', 'Accra', '24339838', '239460.0'), ('Gibraltar', 'Gibraltar', '27884', '6.5'), ('Greenland', 'Nuuk', '56375', '2166086.0'), ('Gambia', 'Bathurst', '1593256', '11300.0'), ('Guinea', 'Conakry', '10324025', '245857.0'), ('Guadeloupe', 'Basse-Terre', '443000', '1780.0'), ('Equatorial Guinea', 'Malabo', '1014999', '28051.0'), ('Greece', 'Athens', '11000000', '131940.0'), ('South Georgia and the South Sandwich Islands', 'Grytviken', '30', '3903.0'), ('Guatemala', 'Guatemala City', '13550440', '108890.0'), ('Guam', 'Hagåtña', '159358', '549.0'), ('Guinea-Bissau', 'Bissau', '1565126', '36120.0'), ('Guyana', 'Georgetown', '748486', '214970.0'), ('Hong Kong', 'Hong Kong', '6898686', '1092.0'), ('Heard Island and McDonald Islands', 'None', '0', '412.0'), ('Honduras', 'Tegucigalpa', '7989415', '112090.0'), ('Croatia', 'Zagreb', '4491000', '56542.0'), ('Haiti', 'Port-au-Prince', '9648924', '27750.0'), ('Hungary', 'Budapest', '9982000', '93030.0'), ('Indonesia', 'Jakarta', '242968342', '1919440.0'), ('Ireland', 'Dublin', '4622917', '70280.0'), ('Israel', 'None', '7353985', '20770.0'), ('Isle of Man', 'Douglas', '75049', '572.0'), ('India', 'New Delhi', '1173108018', '3287590.0'), ('British Indian Ocean Territory', 'None', '4000', '60.0'), ('Iraq', 'Baghdad', '29671605', '437072.0'), ('Iran', 'Tehran', '76923300', '1648000.0'), ('Iceland', 'Reykjavik', '308910', '103000.0'), ('Italy', 'Rome', '60340328', '301230.0'), ('Jersey', 'Saint Helier', '90812', '116.0'), ('Jamaica', 'Kingston', '2847232', '10991.0'), ('Jordan', 'Amman', '6407085', '92300.0'), ('Japan', 'Tokyo', '127288000', '377835.0'), ('Kenya', 'Nairobi', '40046566', '582650.0'), ('Kyrgyzstan', 'Bishkek', '5776500', '198500.0'), ('Cambodia', 'Phnom Penh', '14453680', '181040.0'), ('Kiribati', 'Tarawa', '92533', '811.0'), ('Comoros', 'Moroni', '773407', '2170.0'), ('Saint Kitts and Nevis', 'Basseterre', '51134', '261.0'), ('North Korea', 'Pyongyang', '22912177', '120540.0'), ('South Korea', 'Seoul', '48422644', '98480.0'), ('Kuwait', 'Kuwait City', '2789132', '17820.0'), ('Cayman Islands', 'George Town', '44270', '262.0'), ('Kazakhstan', 'Astana', '15340000', '2717300.0'), ('Laos', 'Vientiane', '6368162', '236800.0'), ('Lebanon', 'Beirut', '4125247', '10400.0'), ('Saint Lucia', 'Castries', '160922', '616.0'), ('Liechtenstein', 'Vaduz', '35000', '160.0'), ('Sri Lanka', 'Colombo', '21513990', '65610.0'), ('Liberia', 'Monrovia', '3685076', '111370.0'), ('Lesotho', 'Maseru', '1919552', '30355.0'), ('Lithuania', 'Vilnius', '2944459', '65200.0'), ('Luxembourg', 'Luxembourg', '497538', '2586.0'), ('Latvia', 'Riga', '2217969', '64589.0'), ('Libya', 'Tripoli', '6461454', '1759540.0'), ('Morocco', 'Rabat', '31627428', '446550.0'), ('Monaco', 'Monaco', '32965', '1.95'), ('Moldova', 'Chişinău', '4324000', '33843.0'), ('Montenegro', 'Podgorica', '666730', '14026.0'), ('Saint Martin', 'Marigot', '35925', '53.0'), ('Madagascar', 'Antananarivo', '21281844', '587040.0'), ('Marshall Islands', 'Majuro', '65859', '181.3'), ('Macedonia', 'Skopje', '2062294', '25333.0'), ('Mali', 'Bamako', '13796354', '1240000.0'), ('Myanmar [Burma]', 'Naypyitaw', '53414374', '678500.0'), ('Mongolia', 'Ulan Bator', '3086918', '1565000.0'), ('Macao', 'Macao', '449198', '254.0'), ('Northern Mariana Islands', 'Saipan', '53883', '477.0'), ('Martinique', 'Fort-de-France', '432900', '1100.0'), ('Mauritania', 'Nouakchott', '3205060', '1030700.0'), ('Montserrat', 'Plymouth', '9341', '102.0'), ('Malta', 'Valletta', '403000', '316.0'), ('Mauritius', 'Port Louis', '1294104', '2040.0'), ('Maldives', 'Malé', '395650', '300.0'), ('Malawi', 'Lilongwe', '15447500', '118480.0'), ('Mexico', 'Mexico City', '112468855', '1972550.0'), ('Malaysia', 'Kuala Lumpur', '28274729', '329750.0'), ('Mozambique', 'Maputo', '22061451', '801590.0'), ('Namibia', 'Windhoek', '2128471', '825418.0'), ('New Caledonia', 'Noumea', '216494', '19060.0'), ('Niger', 'Niamey', '15878271', '1267000.0'), ('Norfolk Island', 'Kingston', '1828', '34.6'), ('Nigeria', 'Abuja', '154000000', '923768.0'), ('Nicaragua', 'Managua', '5995928', '129494.0'), ('Netherlands', 'Amsterdam', '16645000', '41526.0'), ('Norway', 'Oslo', '5009150', '324220.0'), ('Nepal', 'Kathmandu', '28951852', '140800.0'), ('Nauru', 'Yaren', '10065', '21.0'), ('Niue', 'Alofi', '2166', '260.0'), ('New Zealand', 'Wellington', '4252277', '268680.0'), ('Oman', 'Muscat', '2967717', '212460.0'), ('Panama', 'Panama City', '3410676', '78200.0'), ('Peru', 'Lima', '29907003', '1285220.0'), ('French Polynesia', 'Papeete', '270485', '4167.0'), ('Papua New Guinea', 'Port Moresby', '6064515', '462840.0'), ('Philippines', 'Manila', '99900177', '300000.0'), ('Pakistan', 'Islamabad', '184404791', '803940.0'), ('Poland', 'Warsaw', '38500000', '312685.0'), ('Saint Pierre and Miquelon', 'Saint-Pierre', '7012', '242.0'), ('Pitcairn Islands', 'Adamstown', '46', '47.0'), ('Puerto Rico', 'San Juan', '3916632', '9104.0'), ('Palestine', 'None', '3800000', '5970.0'), ('Portugal', 'Lisbon', '10676000', '92391.0'), ('Palau', 'Melekeok', '19907', '458.0'), ('Paraguay', 'Asunción', '6375830', '406750.0'), ('Qatar', 'Doha', '840926', '11437.0'), ('Réunion', 'Saint-Denis', '776948', '2517.0'), ('Romania', 'Bucharest', '21959278', '237500.0'), ('Serbia', 'Belgrade', '7344847', '88361.0'), ('Russia', 'Moscow', '140702000', '1.71E7'), ('Rwanda', 'Kigali', '11055976', '26338.0'), ('Saudi Arabia', 'Riyadh', '25731776', '1960582.0'), ('Solomon Islands', 'Honiara', '559198', '28450.0'), ('Seychelles', 'Victoria', '88340', '455.0'), ('Sudan', 'Khartoum', '35000000', '1861484.0'), ('Sweden', 'Stockholm', '9828655', '449964.0'), ('Singapore', 'Singapore', '4701069', '692.7'), ('Saint Helena', 'Jamestown', '7460', '410.0'), ('Slovenia', 'Ljubljana', '2007000', '20273.0'), ('Svalbard and Jan Mayen', 'Longyearbyen', '2550', '62049.0'), ('Slovakia', 'Bratislava', '5455000', '48845.0'), ('Sierra Leone', 'Freetown', '5245695', '71740.0'), ('San Marino', 'San Marino', '31477', '61.2'), ('Senegal', 'Dakar', '12323252', '196190.0'), ('Somalia', 'Mogadishu', '10112453', '637657.0'), ('Suriname', 'Paramaribo', '492829', '163270.0'), ('South Sudan', 'Juba', '8260490', '644329.0'), ('São Tomé and Príncipe', 'São Tomé', '175808', '1001.0'), ('El Salvador', 'San Salvador', '6052064', '21040.0'), ('Sint Maarten', 'Philipsburg', '37429', '21.0'), ('Syria', 'Damascus', '22198110', '185180.0'), ('Swaziland', 'Mbabane', '1354051', '17363.0'), ('Turks and Caicos Islands', 'Cockburn Town', '20556', '430.0'), ('Chad', "N'Djamena", '10543464', '1284000.0'), ('French Southern Territories', 'Port-aux-Français', '140', '7829.0'), ('Togo', 'Lomé', '6587239', '56785.0'), ('Thailand', 'Bangkok', '67089500', '514000.0'), ('Tajikistan', 'Dushanbe', '7487489', '143100.0'), ('Tokelau', 'None', '1466', '10.0'), ('East Timor', 'Dili', '1154625', '15007.0'), ('Turkmenistan', 'Ashgabat', '4940916', '488100.0'), ('Tunisia', 'Tunis', '10589025', '163610.0'), ('Tonga', "Nuku'alofa", '122580', '748.0'), ('Turkey', 'Ankara', '77804122', '780580.0'), ('Trinidad and Tobago', 'Port of Spain', '1228691', '5128.0'), ('Tuvalu', 'Funafuti', '10472', '26.0'), ('Taiwan', 'Taipei', '22894384', '35980.0'), ('Tanzania', 'Dodoma', '41892895', '945087.0'), ('Ukraine', 'Kiev', '45415596', '603700.0'), ('Uganda', 'Kampala', '33398682', '236040.0'), ('U.S. Minor Outlying Islands', 'None', '0', '0.0'), ('United States', 'Washington', '310232863', '9629091.0'), ('Uruguay', 'Montevideo', '3477000', '176220.0'), ('Uzbekistan', 'Tashkent', '27865738', '447400.0'), ('Vatican City', 'Vatican City', '921', '0.44'), ('Saint Vincent and the Grenadines', 'Kingstown', '104217', '389.0'), ('Venezuela', 'Caracas', '27223228', '912050.0'), ('British Virgin Islands', 'Road Town', '21730', '153.0'), ('U.S. Virgin Islands', 'Charlotte Amalie', '108708', '352.0'), ('Vietnam', 'Hanoi', '89571130', '329560.0'), ('Vanuatu', 'Port Vila', '221552', '12200.0'), ('Wallis and Futuna', 'Mata-Utu', '16025', '274.0'), ('Samoa', 'Apia', '192001', '2944.0'), ('Kosovo', 'Pristina', '1800000', '10908.0'), ('Yemen', 'Sanaa', '23495361', '527970.0'), ('Mayotte', 'Mamoudzou', '159042', '374.0'), ('South Africa', 'Pretoria', '49000000', '1219912.0'), ('Zambia', 'Lusaka', '13460305', '752614.0'), ('Zimbabwe', 'Harare', '11651858', '390580.0')]
Then, we create a list with the column names for our DataFrame:
= ["Name", "Capital", "Population", "Area"] cols
Finally, we can create our DataFrame:
= pd.DataFrame(ls, columns=cols) df
type(df)
pandas.core.frame.DataFrame
print(df)
Name Capital Population Area
0 Andorra Andorra la Vella 84000 468.0
1 United Arab Emirates Abu Dhabi 4975593 82880.0
2 Afghanistan Kabul 29121286 647500.0
3 Antigua and Barbuda St. John's 86754 443.0
4 Anguilla The Valley 13254 102.0
.. ... ... ... ...
245 Yemen Sanaa 23495361 527970.0
246 Mayotte Mamoudzou 159042 374.0
247 South Africa Pretoria 49000000 1219912.0
248 Zambia Lusaka 13460305 752614.0
249 Zimbabwe Harare 11651858 390580.0
[250 rows x 4 columns]