大数据时代,企业和个人都想通过数据分析来获取信息、了解行业和竞对、解决业务问题。那数据从何而来?正如我们平时有问题找“度娘”一样,数据的一个重要来源就是互联网,爬虫就是获取互联网数据的手段,前端时间本数据分析狮,兼职了两周的爬虫工程师,今天跟大家白话白话爬虫那些事儿。
白话爬虫爬虫官方定义:网络爬虫(又称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常被称为网页追逐者),是一种按照一定的规则,自动地抓取万维信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。
白话爬虫:利用程序模拟人的上网行为进行网络索引,获取网页中特定的信息,实现短时间、不间断、实时获取网络数据。
个人浏览器上网原理图
爬虫程序可以简单想象为替代浏览器的功能【发送url请求,解析服务器返回的HTML文档】并将获取的数据存储到数据库或文件中,同时针对网站的反爬策略,需要对自己进行伪装,也就是跟浏览器发送的信息一样携带上我是谁?(cookie信息)、我从哪里来(IP地址,使用代理IP)、我的浏览器型号(User-Agent)、使用的方法(get、post等)、访问的信息。
爬虫原理图
python爬虫代码案例需求:爬取某一关键字(用户自定义)的百度前几页(用户自定义)的搜索结果的网站地址和主题
代码:
class crawler:
'''按关键词爬取百度搜索页面内容'''
url = ''
urls = []
o_urls = []
html = ''
total_pages = 5
current_page = 0
next_page_url = ''
timeout = 60
headersParameters = {
'Connection': 'Keep-Alive',
'Accept': 'text/html, application/xhtml xml, */*',
'Accept-Language': 'en-US,en;q=0.8,zh-Hans-CN;q=0.5,zh-Hans;q=0.3',
'Accept-Encoding': 'gzip, deflate',
'User-Agent': 'Mozilla/6.1 (Windows NT 6.3; WOW64; Trident/7.0; rv:11.0) like Gecko'
}
def __init__(self, keyword):
self.keyword = keyword
self.url = 'https://www.baidu.com/baidu?wd=' quote(keyword) '&tn=monline_dg&ie=utf-8'
self.url_df = pd.DataFrame(columns=["url"])
self.url_title_df = pd.DataFrame(columns=["url","title"])
def set_timeout(self, time):
'''设置超时时间,单位:秒'''
try:
self.timeout = int(time)
except:
pass
def set_total_pages(self, num):
'''设置总共要爬取的页数'''
try:
self.total_pages = int(num)
except:
pass
def set_current_url(self, url):
'''设置当前url'''
self.url = url
def switch_url(self):
'''切换当前url为下一页的url
若下一页为空,则退出程序'''
if self.next_page_url == '':
sys.exit()
else:
self.set_current_url(self.next_page_url)
def is_finish(self):
'''判断是否爬取完毕'''
if self.current_page >= self.total_pages:
return True
else:
return False
def get_html(self):
'''爬取当前url所指页面的内容,保存到html中'''
r = requests.get(self.url ,timeout=self.timeout, headers=self.headersParameters)
if r.status_code==200:
self.html = r.text
# print("-----------------------------------------------------------------------")
# print("[当前页面链接]: ",self.url)
# #print("[当前页面内容]: ",self.html)
# print("-----------------------------------------------------------------------")
self.current_page = 1
else:
self.html = ''
print('[ERROR]',self.url,'get此url返回的http状态码不是200')
def get_urls(self):
'''从当前html中解析出搜索结果的url,保存到o_urls'''
o_urls = re.findall('href\=\"(http\:\/\/www\.baidu\.com\/link\?url\=.*?)\" class\=\"c\-showurl\"', self.html)
titles = re.findall('href\=\"(http\:\/\/www\.baidu\.com\/link\?url\=.*?)\" class\=\"c\-showurl\".* data-tools=\'{"title":(.*?),"url"',self.html)
# o_urls = list(set(o_urls)) #去重
# titles = list(set(titles)) #去重
self.titles = titles
self.o_urls = o_urls
#取下一页地址
next = re.findall(' href\=\"(\/s\?wd\=[\w\d\%\&\=\_\-]*?)\" class\=\"n\"', self.html)
if len(next) > 0:
self.next_page_url = 'https://www.baidu.com' next[-1]
else:
self.next_page_url = ''
def get_real(self, o_url):
'''获取重定向url指向的网址'''
r = requests.get(o_url, allow_redirects = False) #禁止自动跳转
if r.status_code == 302:
try:
return r.headers['location'] #返回指向的地址
except:
pass
return o_url #返回源地址
def transformation(self):
'''读取当前o_urls中的链接重定向的网址,并保存到urls中'''
self.urls = []
for o_url in self.o_urls:
self.urls.append(self.get_real(o_url))
def print_urls(self):
'''输出当前urls中的url'''
for url in self.urls:
print(url)
for title in self.titles:
print(title[0])
def stock_data(self):
url_df = pd.DataFrame(self.urls,columns=["url"])
o_url_df = pd.DataFrame([self.o_urls,self.urls],index=["o_url","url"]).T
title_df = pd.DataFrame(self.titles,columns=["o_url","title"])
url_title_df = pd.merge(o_url_df,title_df,left_on="o_url",right_on="o_url",how="left")
url_titles_df = url_title_df[["url","title"]]
self.url_df = self.url_df.append(url_df,ignore_index=True)
self.url_title_df = self.url_title_df.append(url_titles_df,ignore_index=True)
self.url_title_df["keyword"] = len(self.url_title_df)* [self.keyword]
def print_o_urls(self):
'''输出当前o_urls中的url'''
for url in self.o_urls:
print(url)
def run(self):
while(not self.is_finish()):
self.get_html()
self.get_urls()
self.transformation()
c.print_urls()
self.stock_data()
time.sleep(10)
self.switch_url()
API接口
##爬取百度关键词
timeout = 60
totalpages=2 ##前两页
baidu_url = pd.DataFrame(columns=["url","title","keyword"])
keyword="数据分析"
c = crawler(keyword)
if timeout != None:
c.set_timeout(timeout)
if totalpages != None:
c.set_total_pages(totalpages)
c.run()
# print(c.url_title_df)
baidu_url=baidu_url.append(c.url_title_df,ignore_index=True)
获取关键词“数据分析”的百度搜索结果的前两页信息