赞
踩
目录
参考:百度百科~爬虫
网络爬虫(又称为网页蜘蛛,网络机器人,在FOAF社区中间,更经常的称为网页追逐者),是一种按照一定的规则,自动地抓取html网页信息的程序或者脚本。另外一些不常使用的名字还有蚂蚁、自动索引、模拟程序或者蠕虫。
用python3!python3!python3!python2已经过时了
管理将要爬取的url和已经爬取的url,将待爬取的url传送给网页下载器。
将url指定的网页下载下来,保存为一个json字符串,然后将这个字符串传送给html解析器解析。
download packages:requests, urllib
html download包含三个核心部分:
- # 访问、下载html网页
- url = 'https://baike.baidu.com/item/' + urllib.parse.quote(content) # 请求地址
- # 请求头部,伪造浏览器,防止爬虫被反
- headers = {
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
- }
- # 利用请求地址和请求头部构造请求对象
- req = urllib.request.Request(url=url, headers=headers, method='GET')
- response = urllib.request.urlopen(req) # 发送请求,获得响应
- text = response.read().decode('utf-8') # 读取响应,获得文本
urllib.parse.quote(content) <--因为url只允许一部分ascii字符,其他字符(如汉子)是不符合标准的,此时就要进行编码。
urllib.request.Request --> urlopen()方法可以实现最基本构造HTTP请求的方法,但如果加入headers等信息,就可以利用Request类来构造请求。
- #coding=utf-8
- import requests
- from bs4 import BeautifulSoup
-
- resp=requests.get('https://www.baidu.com') #请求百度首页
- print(resp) #打印请求结果的状态码
- print(resp.content) #打印请求到的网页源码
-
- bsobj=BeautifulSoup(resp.content,'lxml') #将网页源码构造成BeautifulSoup对象,方便操作
- a_list=bsobj.find_all('a') #获取网页中的所有a标签对象
- text='' # 创建一个空字符串
- for a in a_list:
- href=a.get('href') #获取a标签对象的href属性,即这个对象指向的链接地址
- text+=href+'\n' #加入到字符串中,并换行
- with open('url.txt','w') as f: #在当前路径下,以写的方式打开一个名为'url.txt',如果不存在则创建
- f.write(text) #将text里的数据写入到文本中
-->注意:百度爬取的html有静态页面和动态页面。静态简单,比如百度百科;动态困难,比如淘女郎,参考:python爬虫入门教程(三):淘女郎爬虫 ( 接口解析 | 图片下载 )-CSDN博客
一方面,html parser会解析出有价值的数据;另一方面,解析出字符串中的url,将其补充到url管理器。这三个模块形成了一个循环,只要有未爬取的url,这个循环就会一直继续下去。
parser packages: bs4, lxml, xpath。正则表达式用于提取解析器提取不到的数据!!!
html parser包含三个核心内容:
将网页源码解析成BeautifulSoup对象,方便操作
抽取标签方法:find()方法、find_all()方法、select()方法
获取标签文本、属性值方法:text()方法、get_text()方法、get()方法
具体方法介绍,看我的第二篇博客:python爬虫基础(二)~工具包: 下载包requests、urllib和解析包BeautifulSoup(bs4)、xpath,python爬虫基础(二)~工具包: 下载包requests、urllib和解析包BeautifulSoup(bs4)、lxml.etree.xpath_etree与beautifulsoup-CSDN博客
- # 爬取图片
- # 找到所有img标签,返回一个url的标签列表
- img_urllist = []
- resp = requests.get(url=url, headers=headers)
- content = resp.content
- soup = BeautifulSoup(content, 'lxml')
- # img_list = soup.select('div .album-wrap')
- img_list = soup.select('a>div>img')
- print(img_list)
- for img in img_list:
- try:
- # src = img.find('img').get('src')
- src = img.get('src')
- if re.match(r'https:(.*)image(.*)auto$', src):
- img_urllist.append(src)
- except:
- continue
- def query(content):
- # 请求地址
- url = 'https://baike.baidu.com/item/' + urllib.parse.quote(content)
- # 请求头部
- headers = {
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
- }
- # 利用请求地址和请求头部构造请求对象
- req = urllib.request.Request(url=url, headers=headers, method='GET')
- # 发送请求,获得响应
- response = urllib.request.urlopen(req)
- # 读取响应,获得文本
- text = response.read().decode('utf-8')
- # 构造 _Element 对象
- html = etree.HTML(text)
- # 使用 xpath 匹配数据,得到匹配字符串列表
- sen_list = html.xpath('//div[contains(@class,"lemma-summary")]//text()')
- print(sen_list)
- # 过滤数据,去掉空白
- sen_list_after_filter = [item.strip('\n') for item in sen_list if item != '\n']
- # 将字符串列表连成字符串并返回
- return ''.join(sen_list_after_filter)
source:菜鸟教程,Python open() 函数 | 菜鸟教程
模式 | 描述 |
---|---|
t | 文本模式 (默认)。 |
x | 写模式,新建一个文件,如果该文件已存在则会报错。 |
b | 二进制模式。 |
+ | 打开一个文件进行更新(可读可写)。 |
U | 通用换行模式(不推荐)。 |
r | 以只读方式打开文件。文件的指针将会放在文件的开头。这是默认模式。 |
rb | 以二进制格式打开一个文件用于只读。文件指针将会放在文件的开头。这是默认模式。一般用于非文本文件如图片等。 |
r+ | 打开一个文件用于读写。文件指针将会放在文件的开头。 |
rb+ | 以二进制格式打开一个文件用于读写。文件指针将会放在文件的开头。一般用于非文本文件如图片等。 |
w | 打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb | 以二进制格式打开一个文件只用于写入。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 |
w+ | 打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。 |
wb+ | 以二进制格式打开一个文件用于读写。如果该文件已存在则打开文件,并从开头开始编辑,即原有内容会被删除。如果该文件不存在,创建新文件。一般用于非文本文件如图片等。 |
a | 打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
ab | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。也就是说,新的内容将会被写入到已有内容之后。如果该文件不存在,创建新文件进行写入。 |
a+ | 打开一个文件用于读写。如果该文件已存在,文件指针将会放在文件的结尾。文件打开时会是追加模式。如果该文件不存在,创建新文件用于读写。 |
ab+ | 以二进制格式打开一个文件用于追加。如果该文件已存在,文件指针将会放在文件的结尾。如果该文件不存在,创建新文件用于读写。 |
- with open('url.txt','w') as f: #在当前路径下,以写的方式打开一个名为'url.txt',如果不存在则创建
- f.write(text) #将text里的数据写入到文本中
需要用二进制, 'wb'
- with open(file_path, 'wb') as f:
- f.write(soup.content)
- # 先请求页面,xpath定位表格区域
- res = requests.get('http://www.csres.com/notice/50655.html')
- res_elements = etree.HTML(res.text)
- table = res_elements.xpath('//table[@id="table1"]')
- table = etree.tostring(table[0], encoding='utf-8').decode()
-
- # 调用pandas的read_html方法解析表格数据
- df = pd.read_html(table, encoding='utf-8', header=0)[0]
- results = list(df.T.to_dict().values()) # 转换成列表嵌套字典的格式
-
- 转存为csv文件
- df.to_csv("std.csv", index=False)
-
temp
- # 保存信息框数据到excel
- if not os.path.exists('profile'):
- os.mkdir('profile')
-
- profile_file = project_path + '/profile/' + 'profile.csv'
- field_list = ['中文名', '外文名', '别名', '性别', '学位', '职称', '国籍', '民族', '出生地', '籍贯', '出生日期', '逝世日期',
- '星座', '血型', '身高','体重', '毕业院校', '职业', '经纪公司', '代表作品', '主要成就', '生肖', '语种', '特长', '粉丝名']
- if not os.path.exists(profile_file):
- workbook = xlwt.Workbook(encoding='utf-8')
- output_sheet = workbook.add_sheet('profile_sheet', cell_overwrite_ok=True)
- for i in range(len(field_list)):
- output_sheet.write(0, i, field_list[i])
- workbook.save(profile_file)
-
- rb = xlrd.open_workbook(profile_file)
- rows_num = rb.sheet_by_name('profile_sheet').nrows
- # print(rows_num)
- wb = copy(rb)
- output_sheet = wb.get_sheet(0)
- # print(profile)
- for i in range(len(field_list)):
- if profile_dict.get(field_list[i]):
- output_sheet.write(rows_num, i, profile_dict.get(field_list[i]))
- else:
- continue
- os.remove(profile_file)
- wb.save(profile_file)
- # 请求头部,伪造浏览器,防止爬虫被反
- headers = {
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/67.0.3396.99 Safari/537.36'
- }
- # 创建一个session
- session = requests.Session()
- # 设置用于访问的请求头
- headers = {
- 'accept': 'application/json, text/javascript, */*; q=0.01',
- 'accept-encoding': 'gzip, deflate, br',
- 'accept-language': 'zh-CN,zh;q=0.9',
- 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
- 'origin': 'https://mm.taobao.com',
- 'referer': 'https://mm.taobao.com/search_tstar_model.htm',
- 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36',
- 'x-requested-with': 'XMLHttpRequest',
- }
session是requests库中的一个类,创建session对象进行访问的好处是,session对象能够自动维护访问的cookies信息(通过js修改的cookies信息它是记录不到的)
--> 为啥要记录cookies信息:因为有些站点的服务器会验证你的cookies信息,当cookies信息不正确时,服务器会拒绝你的访问。
--> 设置headers和data的目的:是为了将本次请求伪装成浏览器的请求,并通过传递的数据控制服务器返回我们需要的信息。
————————————————
版权声明:本文为CSDN博主「笔墨留年」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/aaronjny/article/details/80291997
现在html网页基本都采用utf-8编码,在爬虫爬取网页时不必过多关注网页的编解码。
以前,request返回的消息编码为gb2312,我们需要先进行解码decode('utf-8'),才不会出现乱码。比如:淘女郎case,因为主页源码为gbk编码,所以需要先用gbk对其解码。
唯一一个例外时urllib发送url请求获取网页源码时,需要先解码decode('utf-8'),再进行网页解析,不然会出现乱码。
source: 淘女郎case
problem: 爬取的内容是从源码取得的,但是在页面中看到了内容,在源码里面却没有,why?
analysis: 这就是动态页面抓取。当我们访问这个网址的时候,浏览器返回给我们的只有一部分信息。 ==> "数据加载中" 实际上,服务器先给我们返回了这个页面,然后又通过ajax技术,请求了另外一个借口。接口返回了淘女郎们的信息,随后浏览器运行javascript代码,将这些信息填充到先前额页面中。因此,我们才在页面中看到了淘女郎们的信息。
(源码页面 -> 检查 -> 网络 -> 内容信息)
--> attention:需要用二进制binary格式保存图片,即'wb'
problem:pycharm imge not loaded try to open it enternally to fix format problem
analysis:原因是不能用bref图片网址保存图片,需要用src图片网址保存图片
by the way:我送你解析图片标签过程中,过滤无效img图片的正则表达式
- # img_list = soup.select('div .album-wrap')
- img_list = soup.select('a>div>img')
- # print(img_list)
- for img in img_list:
- try:
- # src = img.find('img').get('src')
- src = img.get('src')
- if re.match(r'https:(.*)image(.*)auto$', src):
- img_urllist.append(src)
- except:
- continue
至于为啥用soup.select()而不是soup.find_all()? 我个人认为,select()方法兼容方法更多,更关键的是,它支持提取子标签匹配规则,即:'a>div>img'。
by the way: 提取标签中子标签的属性值
src = img.find('img').get('src')
- import ssl
- ssl._create_default_https_context = ssl._create_unverified_context
- >>> s ='1室1厅1卫 \xa0\xa0\xa0\xa038㎡'
- >>> "" .join(s. split())
- '1室1厅1卫38㎡'
- # 删除爬取到html内容中的nbsp:str.replace(u'\xa0', u' ')
- row_content = re.sub('\n', '', row_content.replace(u'\xa0', u' '))
- br_text_list.append(row_content + '\n')
BeautifulSoup_object的previous_sibling、previous_siblings 和 next_sibling、next_siblings方法,可以获取同级标签文本,即兄弟节点的文本。
source:Python html中一级元素.next_sibling打印为空_beautifulsoup兄弟节点打印空白-CSDN博客;Beatifulsoup4 兄弟节点 next_sibling和next_sibling()_bs4 select兄弟节点-CSDN博客
- sibling_soup = BeautifulSoup(sibling_html, 'html.parser')
- br = sibling_soup.p
- while br.next_sibling != None:
- print br
- br = br.next_sibling
- ---------------------------------------------------------------
- for tag in soup.select('div .col-md-4'):
- if tag.get_text() == 'Total':
- result = tag.next_sibling.get_text()
-
--> 判断each br in 返回的标签兄弟节点列表 是否是标签,因为有些兄弟节点为空。
- for br in i.next_siblings: # 获取人物履历标签后面所有的兄弟标签
- # print(br)
- if type(br) is bs4.element.Tag: # 判断br是不是一个标签
- attrs = ''.join(br.attrs['class'])
- if attrs == 'para':
- br_text_list.append(br.get_text())
- elif attrs == re.compile('para-title level'):
- break
- else:
- continue
source:http://www.voidcn.com/article/p-eqwgopwx-bvx.html
- from bs4 import BeautifulSoup
-
- soup = BeautifulSoup("""
- <html><div class="lead">lead</div>data<div class="end"></div></html>"
- """, "lxml")
-
- node = soup.find('div', {'class': 'lead'})
- s = []
- while True:
- if node is None:
- break
- node = node.next_sibling
- if hasattr(node, "attrs") and ("end" in node.attrs['class'] ):
- break
- else:
- if node is not None:
- s.append(node)
- print s
[1] 爬虫实战(一) 用Python爬取百度百科, https://www.cnblogs.com/wsmrzx/p/10531708.html
[2] python爬虫入门教程(二):开始一个简单的爬虫, python爬虫入门教程(二):开始一个简单的爬虫_python 爬虫-CSDN博客
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。