您的位置:首页 > 编程语言 > Python开发

python爬虫(1)——简单的爬取网页的信息

2018-02-03 15:01 459 查看
获取网上真实的语料数据,本身对Py的掌握不是很好,记录下自己学习的过程,希望对你有帮助。
#python3
获得taoeba的语料(不知道从哪翻到的这个网站,有各国语言的句子,访问速度较慢

# -*- coding: utf-8 -*-
import requests
from bs4 import BeautifulSoup as BS
import time
import re

python3中的urllib以及requestshttp://blog.csdn.net/drdairen/article/details/51149498
#对句子列表网页进行获取,得到一个list包含句子链接
def get_selist(url):
try:
response = requests.get(url, headers=headers) #访问所有句子列表
soup = BS(response.text, "lxml")  #解析网页
urls = soup.find_all(href=re.compile('.*/cmn/sentences/show/[0-9].*')) #找到所有我要的<a>标签  得到一个list  接下来提取元素的href
sentences = [] #存href
for i in urls:  #遍历<a>标签列表
sentences.append(i.get('href')) #get('href')只能对标签字符串操作,刚开始我直接对urls.get()是不可以的。。。
sentences = list(set(sentences)) #对得到的href列表去重
return sentences  #返回链接的list
except Exception as e:  #网页访问错误就返回空列表
a = []
print('获取句子列表失败  链接为'+url)
return a


headers = {'User-Agent':'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36'}
url = 'https://tatoeba.org/cmn/sentences/show_all_in/cmn/none/none/indifferent/page:'      #分析发现所有中文句子的网页规律
h = 'https://tatoeba.org'     #为了访问词的地址  地址一般为../cmn/sentences/show/[0-9]

header用来假装自己是个浏览器,有时也会需要cookie等。
查看你的浏览器的user-agent ——地址栏中输入:about:version   查看user-agents
直接脚本访问,可能会出现这样的报错:
...
...
urllib.error.HTTPError: HTTP Error 403: Forbidden

#对句子列表网页进行获取,得到一个list包含句子链接
def get_selist(url):
try:
response = requests.get(url, headers=headers) #访问所有句子列表
soup = BS(response.text, "lxml")  #解析网页
urls = soup.find_all(href=re.compile('.*/cmn/sentences/show/[0-9].*')) #找到所有我要的<a>标签  得到一个list  接下来提取元素的href
sentences = [] #存href
for i in urls:  #遍历<a>标签列表
sentences.append(i.get('href')) #get('href')只能对标签字符串操作,刚开始我直接对urls.get()是不可以的。。。
sentences = list(set(sentences)) #对得到的href列表去重
return sentences  #返回链接的list
except Exception as e:  #网页访问错误就返回空列表
a = []
print('获取句子列表失败  链接为'+url)
return a


# 解析一个词的网页  返回fr/es的两个列表[zh:fr,zh:fr],[zh:sp,zh:sp]
def getext(url1):
def text(tag):#内置函数,传入一个标签列表,获得每一个text信息,返回一个list
a = []
for i in tag:
a.append(i.get_text())
return a
try:
response = requests.get(url1, headers=headers)#同上
soup = BS(response.text, "lxml")
zh = text(soup.find_all('div', attrs={'lang': 'zh-Hans'})) #获得对应属性的标签  这个找的是含有中文的标签
fr = text(soup.find_all('div', attrs={'lang': 'fr'}))#法语
sp = text(soup.find_all('div', attrs={'lang': 'es'}))  #西班牙语
zh2fr = []
zh2sp = []  #两个list存对应语料信息
for f in fr:   #将对应语料格式化
zh2fr.append(zh[0] + '||||' + f)
for s in sp:
zh2sp.append(zh[0] + '||||' + s)
print(zh2fr, zh2sp)
return zh2fr, zh2sp #返回两个列表,方便写入两个文件
except Exception as e:  #同样错误则返回空
a = []
b = []
print('获取句子失败  链接为'+url1)
return a,b


#因为得到的是对应语料的list  构造一个函数  方便写入文件
def _write(file,fr):
if len(fr):
for i in fr:
file.write(i+'\n')


#开始的操作~
zh2fr = open('zh2fr','a',encoding='utf-8')  #将要写入的两个文件
zh2sp = open('zh2sp','a',encoding='utf-8')
url_list = []

#获得所有句子的链接,应该是有5094页,取了一页测试
for i in range(1,2):
url_list.extend(get_selist(url+str(i))) #将列表连在一起

begin = time.time() #时间记录

#访问所有的句子链接,获得平行语料并写入文件
for j in url_list:
(fr,sp) = getext(h+j)
_write(zh2fr,fr)
_write(zh2sp,sp)
end = time.time()

print('use time %s'%(end-begin))

#对了,不要忘了close打开的文件
zh2ru.close()
zh2fr.close()

这个脚本的效率不是很高,首先因为网站访问很慢,时间不一定(一套下来10多秒也有可能,几百秒也有可能。。)
其次因为单线程,下面是我更改后的代码,用了多线程,参考https://zhuanlan.zhihu.com/p/25228075

# 主要加了sleep random  避免访问过快
# 解析一个词的网页  返回fr/es的两个列表[zh:fr,zh:fr]
#多加了一门语言
def getext(url1):
def text(tag):
a = []
for i in tag:
a.append(i.get_text())
return a
try:
time.sleep(random.randint(0,5))   #避免句子同时访问太快。。没有对线程任务的时间控制,感觉这么写比较简单。。
response = requests.get(url1, headers=headers)
soup = BS(response.text, "lxml")
zh = text(soup.find_all('div', attrs={'lang': 'zh-Hans'}))
fr = text(soup.find_all('div', attrs={'lang': 'fr'}))
sp = text(soup.find_all('div', attrs={'lang': 'es'}))
ru = text(soup.find_all('div', attrs={'lang': 'ru'}))
zh2fr = []
zh2sp = []
zh2ru = []
for f in fr:
zh2fr.append(zh[0] + '||||' + f)
for s in sp:
zh2sp.append(zh[0] + '||||' + s)
for r in ru:
zh2ru.append(zh[0] + '||||' + r)
print(zh2fr, zh2sp, zh2ru)
return zh2fr, zh2sp, zh2ru
except Exception as e:
a = []
print('获取句子失败  链接为'+url1)
return a,a,a


# 主要加了这个函数  获得句子链接没有用多线程,访问句子网页用的,因为访问太快会报错。。虽然不会被封,但是无法获得信息了
#访问一页,就获取所有的句子,避免了过快访问
def get_url(i):
url_list = (get_selist(url + str(i)))                                                                             #获得句子的网址列表,用的写好的函数。
print('page'+str(i)+'ok---'+str(len(url_list)))
def fetch_content(url):                                                                                            #任务函数
(fr, sp, ru) = getext(h + url)
_write(zh2fr, fr)
_write(zh2sp, sp)
_write(zh2ru, ru)
threads2 = []                                                                                                            #多线程任务的封装
for j in url_list:
t = Thread(target=fetch_content, args=[j])
t.start()
threads2.append(t)
for t in threads2:
t.join()


这样比单线程快了许多,爬取网页信息还是不要访问太快了。。对网站的服务器友好一点。。

下一步将要学习一下动态网页信息的爬取,通过scrapy

深入了解一下线程进程,以及网络爬虫机制(操作系统?网络?)

发现什么问题,或者有什么建议请告诉我~谢谢~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  python 爬虫