网络爬虫
网络爬虫(web crawler),以前经常称之为网络蜘蛛,是按照一定的规则自动浏览万维网并获取信息的机器人程序(或脚本),曾经被广泛的应用于互联网搜索引擎。使用过互联网和浏览器的人都知道,网页中除了供用户阅读的文字信息之外,还包含一些超链接。网络爬虫系统正是通过网页中的超链接信息不断获得网络上的其它页面。正因如此,网络数据采集的过程就像一个爬虫或者蜘蛛在网络上漫游,所以才被形象的称为网络爬虫或者网络蜘蛛。
爬虫的应用领域
在理想的状态下,所有ICP(Internet Content Provider)都应该为自己的网站提供API接口来共享它们允许其他程序获取的数据,在这种情况下爬虫就不是必需品,国内比较有名的电商平台(如淘宝、京东等)、社交平台(如腾讯微博等)等网站都提供了自己的Open API,但是这类Open API通常会对可以抓取的数据以及抓取数据的频率进行限制。对于大多数的公司而言,及时的获取行业相关数据是企业生存的重要环节之一,然而大部分企业在行业数据方面的匮乏是其与生俱来的短板,合理的利用爬虫来获取数据并从中提取出有价值的信息是至关重要的。当然爬虫还有很多重要的应用领域,以下列举了其中的一部分:
- 搜索引擎
- 新闻聚合
- 社交应用
- 舆情监控
- 行业数据
合法性和背景调研
- 网络爬虫领域目前还属于拓荒阶段,虽然互联网世界已经通过自己的游戏规则建立起一定的道德规范(Robots协议,全称是“网络爬虫排除标准”),但法律部分还在建立和完善中,也就是说,现在这个领域暂时还是灰色地带。
- “法不禁止即为许可”,如果爬虫就像浏览器一样获取的是前端显示的数据(网页上的公开信息)而不是网站后台的私密敏感信息,就不太担心法律法规的约束,因为目前大数据产业链的发展速度远远超过了法律的完善程度。
- 在爬取网站的时候,需要限制自己的爬虫遵守Robots协议,同时控制网络爬虫程序的抓取数据的速度;在使用数据的时候,必须要尊重网站的知识产权(从Web 2.0时代开始,虽然Web上的数据很多都是由用户提供的,但是网站平台是投入了运营成本的,当用户在注册和发布内容时,平台通常就已经获得了对数据的所有权、使用权和分发权)。如果违反了这些规定,在打官司的时候败诉几率相当高。
一个简单的爬虫
构造一个爬虫一般分为数据采集丶数据处理和数据存储三个部分的内容。
解析页面:
1.正则表达式 优势:性能好 劣势:非常的复杂
2.pyquery —JQuwey — css 选择器取元素
3.BeautifulSoup bs4
4.lxml —-libxml2 —-xpath
原生代码爬 (了解一下,能看懂就行,不常用)
from urllib.error import URLError
from urllib.request import urlopen
import re
import pymysql
def get_page_code(start_url, *, retry_times=3, charsets=('utf-8',)):
try:
for charset in charsets:
try:
html = urlopen(start_url).read().decode(charset)
break
except UnicodeDecodeError:
html = None
except URLError as ex:
print('Error:', ex)
return get_page_code(start_url, retry_times - 1,charsets=('utf-8','gbk','gb2312')) if \
retry_times > 0 else None
return html
def main():
url_list = ['http://sports.sohu.com/nba_a.shtml']
visited_list = set({})
while len(url_list) > 0:
current_url = url_list.pop(0)
visited_list.add(current_url)
html = get_page_code(current_url, charsets=('gbk','utf8'))
if html:
link_regex = re.compile(r'<a[^>]+test=a\s[^>]*href=["\'](\S*)["\']', re.IGNORECASE)
link_list = re.findall(link_regex, html)
url_list += link_list
conn = pymysql.connect(host='localhost',port=3306,
db='crawler',user='root',passwd='123456',
charset='utf8mb4')
try:
for link_url in link_list:
if link_url not in visited_list:
visited_list.add(link_url)
html1 = get_page_code(link_url, charsets=('utf-8','gbk','gb2312'))
title_regex = re.compile(r'<h1>(.*)<span',re.IGNORECASE)
match_list = re.findall(title_regex, html1)
if len(match_list) > 0:
title = match_list[0]
with conn.cursor() as cursor:
cursor.execute('insert into tb_result(rtitle,rurl) values(%s,%s)',
(title,link_url))
conn.commit()
finally:
conn.close()
print('执行结束')
if __name__ == '__main__':
main()
常用的爬虫代码,
我们需要安装相应的库:
pip install bs4 # 包含BeautifulSoup
pip install lxml
pip install pymysql # 连接数据库的包
我们常用的是BeautifulSoup, 相关文档BeautifulSoup文档
第一个爬虫:
from bs4 import BeautifulSoup
import requests
import re
def main():
# 通过requests第三方库的get方法获取页面
resp = requests.get('http://sports.sohu.com/nba_a.shtml')
# 对响应的字节串(bytes)进行解码操作(搜狐的部分页面用了gbk编码)
html = resp.content.decode('gbk')
# 创建BeautifulSoup对象来解析页面(相当于javascript的DOM)
bs = BeautifulSoup(html, 'lxml')
# 通过CSS选择器语法查找元素并通过循环进行处理
for elem in bs.select('a[test=a]'):
# 通过attrs属性(字典)获取元素的属性值
link_url = elem.attrs['href']
resp = requests.get(link_url)
bs_sub = BeautifulSoup(resp.text, 'lxml')
title = bs_sub.select_one('h1').text
# 使用正则表达式对获取的数据做进一步的处理
print(re.sub(r'[\r\n]', '', title))
if __name__ == '__main__':
main()
爬取天行数据接口中,国内新闻里的相关新闻的连接 代码如下:
from bs4 import BeautifulSoup
import requests
import json
import pymysql
def main():
resp = requests.get('http://api.tianapi.com/guonei/?key=9cc85fdab1b8d022d5571e815d3ba4da&num=10')
mydict = json.loads(resp.text)
list1 = mydict['newslist']
for dict in list1:
url = dict['url']
temp = requests.get(url)
temp.encoding = 'gbk'
html = temp.text
soup = BeautifulSoup(html, 'lxml')
list = soup.select('.list14')
# 连接数据路
conn = pymysql.connect(host='localhost', port=3306,
db='crawler', user='root',
passwd='123456', charset='utf8mb4')
try:
if list:
title = soup.select('h1')[0].text
a_list = list[0].select('ul a')
for elem in a_list:
url = elem.attrs['href']
desc = elem.text
# 创建一个游标
with conn.cursor() as cursor:
cursor.execute('insert into tb_housework(alltitle,title,url) values (%s,%s,%s)',
(title, desc, url))
conn.commit()
finally:
conn.close()
print('执行结束')
if __name__ == '__main__':
main()