在实践爬取网页数据时的流程概述
在看Youtube时, 发现Youtube频道是可以赚钱的,只要自己Youtube频道的观看订阅人数够多,就可以通过投放广告来赚钱。于是自己也异想天开通过Youtube频道赚钱,但又不知哪种类型的频道最为赚钱,于是便想利用自身所学来分析一下Youtube频道的数据,从而做出明智的决定。尝试初期发现Youtube的数据格式不是那么规整,不太好爬取所以先用csdn博客来练练手。
之前从未接触过python爬取网站数据,所以也相当于半个小白,而我的过程也应该非常适合对爬虫感兴趣且无太多经验的小白来看。
文章个人感觉很长,只想玩玩爬虫的可以直接跳到最后拷贝复制运行代码。个人实践当中发现有时会报错如
urllib2.HTTPError: HTTP Error 403: Forbidden
IncompleteRead(81552 bytes read, 14206 more expected)
出现以上两种两种报错时,一般再运行一遍程序就不会报错了,也就是说以上两种报错是偶发性的。后续博客会将我实践当中遇到并解决的报错进行总结,欢迎持续关注我的博客,分享自己所学是我最快乐的事,谢谢!
获取csdn前n页的热门博客的标题,链接,阅读量,评论量,并将这些数据存储到Excel表格当中。
要实现csdn博客信息获取,其功能可粗略划分为如下四个:
通过观察得,csdn网站是由一个个页面组成,而每个页面是由博客标题,作者,阅读量,广告等组成。所以在获取博客标题,作者等信息前要先遍历访问每一个页面。通过观察得知,页面url之间只是page=**
不一样,所以我们可以考虑通过循环并改变page对应的值来遍历所有页面。
详细代码如下:
def url_all(): for page in range(1,3): url = "https://www.csdn.net/?toolbar_logo&page="+str(page) print("将第"+str(page)+"页加入列表url_list") url_list.append(url)
字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。可以使用模块chardet对网页编码进行解析,根据解析结果将网页编码转换,再进行解码。详细内容可参考博客
Python中的编码(encode)与解码(decode)。
详细代码如下:
def Trans_code(blog_url): response = request.urlopen(blog_url) html = response.read() # 进行编码转换与解码,利用模块chardet可以方便检测网页编码 charset = chardet.detect(html) # 将网页编码转换为str,再进行解码 html = html.decode(str(charset["encoding"])) return html
字符串在Python内部的表示是unicode编码,因此,在做编码转换时,通常需要以unicode作为中间编码,即先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。可以使用模块chardet对网页编码进行解析,根据解析结果将网页编码转换,再进行解码。更详细内容可参考博客
Python中的编码(encode)与解码(decode)。
详细代码如下:
def Trans_code(blog_url): response = request.urlopen(blog_url) html = response.read() # 进行编码转换与解码,利用模块chardet可以方便检测网页编码 charset = chardet.detect(html) # 将网页编码转换为str,再进行解码 html = html.decode(str(charset["encoding"])) return html
最后得到的html是Unicode编码的网页。
获取所有由Unicode编码的网页的数据后,我们需要从中提取感兴趣的数据。这里我使用了python中重要的从html文档中提取数据的库Beautiful Soup。关于Beautiful Soup库的详细解释可参考这篇博客Python爬虫利器二之Beautiful Soup的用法。
在使用Beautiful库提取数据时,本文采取了css选择器即方法select()
。在向select()
中填入内容前需先查看网页源码确定要提取数据的位置,网页源码见下图。由图可见,需要获取的数据都在类名class="list_con"
所包含的内容中。通过遍历找出所有class="list_con"
包含的内容。然后分别找到标题对应的标签<a>
,博客链接位置为标签<a>
对应的属性href
,博客作者位置为class="name"
,博客阅读数位置为class="num"
。
在查找数据位置当中,在方法select()
中填入的内容为个人不断尝试得出。本文中尝试方法就是将填充内容更换为离目标数据最近的标签名或类名或属性名,然后观察输出结果,最终确定正确的填充内容。个人总结的关于填入正确查找位置的经验为:
详细代码如下:
def Get_data(html): soup = BeautifulSoup(html, 'html.parser') # 获取到每一个class=list_con的a节点 allList = soup.select('.list_con') # 遍历列表,获取有效信息 # print("网页链接为:", url) print("网页链接为:", blog_url) for news in allList: number = news.select('.num') author = news.select('.name') eassy_title = news.select('a') # 只选择长度大于0的结果 # print("从a节点获取的信息:\n",eassy_title) if len(eassy_title) > 0: # 文章链接 try: # 如果抛出异常就代表为空 href = eassy_title[0]['href'] # href = url + aaa[0]['href'] X.append(href) except Exception: href = '链接为空' # 博客标题 try: # title = aaa[0]['title'] title = eassy_title[0].text Y.append(title) except Exception: title = "标题为空" # 博客阅读数 try: readnum = number[0].text Z.append(readnum) except Exception: readnum = "未知阅读数" # 博客作者 try: who = author[0].text A.append(who) except Exception: who = "无名氏" print("标题", title, "\nurl:", href, "\n阅读量:", readnum, "\n作者:", who)
题外话(慎看):
有兴趣深入研究css选择器者可将之与搜索文档树即方法find_all()
对比学习,参考文档同为Python爬虫利器二之Beautiful Soup的用法。
在浏览有关网页中数据爬取的资料时,发现获取网页数据除了可以调用库Beautiful Soup库外,还可以用正则表达式,库lxml。有兴趣深入研究者可查看博客python抓取网页数据的三种方法。
获取到的数据需要保存至本地.csv
文件。由于获取的数据是标签型数据(如HTML,XML,JSON,YAML等),而标签型数据无法直接存入.csv
表格当中,所以要通过.string
或.text
获取标签内部的文字(即cotent, NavigableString对象),然后将获得的NavigableString对象存入列表当中。将列表转换为字典,再将结果转换为DataFrame
,最后存入表格当中。在将数据存入表格时需要设置编码方式encoding='gbk'
,否则保存的数据会显示乱码。
详细代码如下:
def Save_data(X,Y,Z,A): print("储存数据至表格.......") Table = {"Title": Y, "ReadNumber": Z, "Author": A, "URL": X} df = pd.DataFrame(Table) df.to_csv('Table.csv', encoding='gbk') print("==============================================================================================")
import ssl from bs4 import BeautifulSoup from urllib import request import chardet import xlwt import pandas as pd ssl._create_default_https_context = ssl._create_unverified_context def url_all(): for page in range(1,3): url = "https://www.csdn.net/?toolbar_logo&page="+str(page) print("将第"+str(page)+"页加入列表url_list") url_list.append(url) def Trans_code(blog_url): response = request.urlopen(blog_url) html = response.read() # 进行编码转换与解码,利用模块chardet可以方便检测网页编码 charset = chardet.detect(html) # 将网页编码转换为str,再进行解码 html = html.decode(str(charset["encoding"])) return html def Get_data(html): soup = BeautifulSoup(html, 'html.parser') # 获取到每一个class=list_con的a节点 allList = soup.select('.list_con') # 遍历列表,获取有效信息 # print("网页链接为:", url) print("网页链接为:", blog_url) for news in allList: number = news.select('.num') author = news.select('.name') eassy_title = news.select('a') # 只选择长度大于0的结果 # print("从a节点获取的信息:\n",eassy_title) if len(eassy_title) > 0: # 文章链接 try: # 如果抛出异常就代表为空 href = eassy_title[0]['href'] # href = url + aaa[0]['href'] X.append(href) except Exception: href = '链接为空' # 博客标题 try: # title = aaa[0]['title'] title = eassy_title[0].text Y.append(title) except Exception: title = "标题为空" # 博客阅读数 try: readnum = number[0].text Z.append(readnum) except Exception: readnum = "未知阅读数" # 博客作者 try: who = author[0].text A.append(who) except Exception: who = "无名氏" print("标题", title, "\nurl:", href, "\n阅读量:", readnum, "\n作者:", who) X = [] # X储存所有链接 Y = [] # Y储存所有标题 Z = [] # Z储存所有阅读数 A = [] # A储存所有作者 url_list = [] url_all() for blog_url in url_list: html = Trans_code(blog_url) Get_data(html) print("储存数据至表格.......") Table = {"Title":Y,"ReadNumber":Z,"Author":A,"URL":X} df = pd.DataFrame(Table) df.to_csv('Table.csv',encoding='gbk') print("==============================================================================================")
本文代码在实践中多次修改,有些改动可能并未及时同步到上述代码中,有可能出现报错的情况,由于代码版本过多,且精力不够,我将已验证正确的代码上传至github,如果文中代码运行通不过或希望查看更多版本的代码,可访问我的github源码。