利用Python爬取网站的新手指南Linux中国
爱达荷州FamilyDollar所在地页面首先,让我们在Python虚拟环境中加载先决条件。此处的代码将被添加到一个Python文件(如果你想要个名称,则为scraper.py)或在JupyterLab的单元格中运行。
importrequests#formakingstandardhtmlrequestsfrombs4importBeautifulSoup#magicaltoolforparsinghtmldataimportjson#forparsingdatafrompandasimportDataFrameasdf#premierlibraryfordataorganization接下来,我们从目标URL中请求数据。
page=requests.get("")soup=BeautifulSoup(page.text,'html.parser')BeautifulSoup将HTML或XML内容转换为复杂树对象。这是我们将使用的几种常见对象类型。
BeautifulSoup——解析的内容Tag——标准HTML标记,这是你将遇到的bs4元素的主要类型NavigableString——标签内的文本字符串Comment——NavigableString的一种特殊类型当我们查看requests.get()输出时,还有更多要考虑的问题。我仅使用page.text()将请求的页面转换为可读的内容,但是还有其他输出类型:
page.text()文本(最常见)page.content()逐字节输出page.json()JSON对象page.raw()原始套接字响应(对你没啥用)我只在使用拉丁字母的纯英语网站上操作。requests中的默认编码设置可以很好地解决这一问题。然而,除了纯英语网站之外,就是更大的互联网世界。为了确保requests正确解析内容,你可以设置文本的编码:
page=requests.get(URL)page.encoding='ISO-885901'soup=BeautifulSoup(page.text,'html.parser')仔细研究BeautifulSoup标签,我们看到:
bs4元素tag捕获的是一个HTML标记。它具有名称和属性,可以像字典一样访问:tag['someAttribute']。如果标签具有相同名称的多个属性,则仅访问第一个实例。可通过tag.contents访问子标签。所有标签后代都可以通过tag.contents访问。你始终可以使用以下字符串:re.compile("your_string")访问一个字符串的所有内容,而不是浏览HTML树。确定如何提取相应内容警告:此过程可能令人沮丧。
网站爬取过程中的提取可能是一个令人生畏的充满了误区的过程。我认为解决此问题的最佳方法是从一个有代表性的示例开始然后进行扩展(此原理对于任何编程任务都是适用的)。查看页面的HTML源代码至关重要。有很多方法可以做到这一点。
你可以在终端中使用Python查看页面的整个源代码(不建议使用)。运行此代码需要你自担风险:
print(soup.prettify())虽然打印出页面的整个源代码可能适用于某些教程中显示的玩具示例,但大多数现代网站的页面上都有大量内容。甚至404页面也可能充满了页眉、页脚等代码。
通常,在你喜欢的浏览器中通过“查看页面源代码”来浏览源代码是最容易的(单击右键,然后选择“查看页面源代码”)。这是找到目标内容的最可靠方法(稍后我将解释原因)。
FamilyDollar地图和代码地址信息嵌套在type="application/ld+json"里。经过大量的地理位置抓取之后,我开始认识到这是用于存储地址信息的一般结构。幸运的是,soup.find_all()开启了利用type搜索。
arco=soup2.find_all(type="application/ld+json")print(arco[1])地址信息在第二个列表成员中!原来如此!
使用.contents提取(从第二个列表项中)内容(这是过滤后的合适的默认操作)。同样,由于输出的内容是一个列表,因此我为该列表项建立了索引:
arco_contents=arco[1].contents[0]arco_contents喔,看起来不错。此处提供的格式与JSON格式一致(而且,该类型的名称中确实包含“json”)。JSON对象的行为就像是带有嵌套字典的字典。一旦你熟悉利用其去工作,它实际上是一种不错的格式(当然,它比一长串正则表达式命令更容易编程)。尽管从结构上看起来像一个JSON对象,但它仍然是bs4对象,需要通过编程方式转换为JSON对象才能对其进行访问:
arco_json= json.loads(arco_contents)type(arco_json)print(arco_json)在该内容中,有一个被调用的address键,该键要求地址信息在一个比较小的嵌套字典里。可以这样检索:
arco_address=arco_json['address']arco_address好吧,请大家注意。现在我可以遍历存储爱达荷州URL的列表:
locs_dict=[]#initialiseemptylistforlinkincity_hrefs: locpage=requests.get(link) #requestpageinfo locsoup=BeautifulSoup(locpage.text,'html.parser') #parsethepage'scontent locinfo=locsoup.find_all(type="application/ld+json") #extractspecificelement loccont=locinfo[1].contents[0] #getcontentsfromthebs4elementset locjson=json.loads(loccont) #converttojson locaddr=locjson['address']#getaddress locs_dict.append(locaddr)#addaddresstolist用Pandas整理我们的网站抓取结果我们在字典中装载了大量数据,但是还有一些额外的无用项,它们会使重用数据变得比需要的更为复杂。要执行最终的数据组织,我们需要将其转换为Pandas数据框架,删除不需要的列@type和country,并检查前五行以确保一切正常。
locs_df=df.from_records(locs_dict)locs_df.drop(['@type','addressCountry'],axis=1,inplace=True)locs_df.head(n=5)确保保存结果!!
df.to_csv(locs_df,"family_dollar_ID_locations.csv",sep=",",index=False)我们做到了!所有爱达荷州FamilyDollar商店都有一个用逗号分隔的列表。多令人兴奋。
Selenium和数据抓取的一点说明Selenium是用于与网页自动交互的常用工具。为了解释为什么有时必须使用它,让我们来看一个使用Walgreens网站的示例。“检查元素”提供了浏览器显示内容的代码:如果这两个不一致,是有一些插件可以修改源代码——因此,应在将页面加载到浏览器后对其进行访问。requests不能做到这一点,但是Selenium可以做到。
Selenium需要Web驱动程序来检索内容。实际上,它会打开Web浏览器,并收集此页面的内容。Selenium功能强大——它可以通过多种方式与加载的内容进行交互(请阅读文档)。使用Selenium获取数据后,继续像以前一样使用BeautifulSoup:
url=""driver=webdriver.Firefox(executable_path='mypath/geckodriver.exe')driver.get(url)soup_ID=BeautifulSoup(driver.page_source,'html.parser')store_link_soup=soup_ID.find_all(class_='col-xl-4col-lg-4col-md-4')对于FamilyDollar这种情形,我不需要Selenium,但是当呈现的内容与源代码不同时,我确实会保留使用Selenium。
小结总之,使用网站抓取来完成有意义的任务时:
耐心一点查阅手册(它们非常有帮助)如果你对答案感到好奇: