当前位置: 首页 > 编程日记 > 正文

记录一次爬取某昵称网站的爬虫

同学跑去实习了...然后工作的时候要她用python写一个爬虫,爬取一万个可以用的用户昵称。(为什么他们都能找到工作啊QAQ)

然后,她找到了我...然后在我动笔的时候,发现之前写过的爬虫基本上忘完了...无奈下只好对着以前写的项目,重新找了下文章,现在写一篇文章重新集合下之前零散的知识点。

我这里写的内容只是针对自己的需求写的,如果想要彻底了解BeautifulSoup的用法的话,可以参考下这篇文章: () => 文章 (看完这文章我都想敲一下Java8新增的lambda表达式了...真的超级炫酷的)

跳过基础内容讲解的话,点我

言归正传,开始吧。


python的爬虫,可能会用到两个包(过去是这样的),一个是BeautifulSoup,一个是etree

我用我的理解简单说说这两个包吧(这里的话十有八九别信...)

BeautifulSoup:

  • 一个抓取页面的插件,能够页面抓取出来,能对页面数据做简单的筛选
  • 引入方法: from bs4 import BeautifulSoup
  • 安装方法: pip install bs4

etree:

  • 在3.7(应该是3.7)版本以前,都是特别好用的,因为里面可以用XPath直接锁定DOM元素,但是在未来的更新中,它对XPath的兼容性并不好,所以干脆砍掉了。注:在谷歌浏览器里可以直接复制出页面的XPath,所以个人感觉没有必要去记XPath语法,毕竟我们可不是因为玩爬虫而玩python的,要知道,python可是因为人工智能而一鸣惊人。
  • 引入方式: from lxml import etree(这个词应该是Element Tree)
  • 安装方式: pip install lxml
  • 据说在4.1.1版本里可以通过from lxml.html import etree使用etree
  • 想要使用的话,可以用pip指定版本安装,安装过去的版本使用

因为我目前不是很想在这爬虫上折腾,所以这次就用了BeautifulSoup写完了本次的爬虫,这里就不对etree的用法做介绍了,想了解的话根据自己安装的lxml版本换一篇文章,就不浪费时间了

先来说说BeautifulSoup的四种数据类型,为了以后做铺垫:

  1. Tag
  2. NavigatableString
  3. BeautifulSoup
  4. Comment

Tag => 就是页面里的标签;

NavigableString => 如果你想获取Tag中的文字,你可以用TagName.string获取里面的内容,获取的值便是NavigableString类型的对象;

BeautifulSoup => 它是个功能更多的对象,你可以使用更多的方式获取子类的对象,获取方式很简单,举个栗子:

soup = BeautifulSoup(你就想象这里有很长很长很长的html代码吧, 'lxml')  # 获取页面文档 这是个BeautifulSoup类型的数据# 如果愿意的话,可以用 print(type(soup)) 检查下 soup 的数据类型,我没有测试item = soup.find_all(name='a', attrs={'class': 'hover', 'target': '_self'})  
# 这里用的 find_all 方法,意思就是找到之前获取的文档对象(soup)下的所有满足<a class='hover' target='_self'></a>的对象

Comment => 这个属性比较特殊了,它可以找到所有的注释内容...没用过

对于BeautifulSoup对象有很多属性可以用,比如说:

  • 靠标签名查找 => soup.select('div')
  • 靠选择器查找 => soup.select('.top-bar')
  • 靠id查找 => soup.select('#app')
  • 组合的 => soup.select('#app .top-bar')
  • 子类的 => soup.select('#app > .top-bar')
  • 具体 => soup.select('div[data="NickName" class="name"]') # 这里可以了解下Emmet语法,挺像的...方括号里的是属性,大括号里的是内容,中间不能有空格。

参考的文章 => 现在想想...我当初为什么没有用select来写...

基础东西讲完了...后面的感觉完全不用看了,如果你闲着没事干的话

正式开始上代码

靶机 (用靶机这个词是不是感觉特别装逼啊)

http://www.oicq88.com

思路

  1. 获取到页面元素

  2. 检查下文档页面后,发现它把昵称分成了很多类别,一共五十多个,点进去之后,会进入子域名,使用字符串拼接直接访问内部链接即可

  3. 每一个类别里有很多页数据,我们需要优先知道页面总数,才可以去遍历,至少不会出现角标越界的状况,无意间发现,在页面后面拼接的数字超出是不会报错的,并且能看到的页面是该网站的最后一页(我在说什么啊) | 其实还有个思路,爬完一页之后判断是否还有下一页,如果有,则继续向后遍历,没有则退出循环。

  4. 利用BeautifulSoup获取到所有的昵称内容(为什么不能前后台分离用,前台向后台请求json数据,这样我就能直接拿到所有的昵称了...也不知道这个是伪静态还是静态)

  5. IO流,文件的写入

大纲

  1. 拿到页面元素,也就是document文档
  2. 拼接得到所有昵称类型
  3. 分析状况
  4. 拿到每种类型的页数
  5. 遍历每一页,并将数据写入文件中

拿到拿到页面元素

拿页面元素,很简单的

response = requests.get(url='http://www.oicq88.com')

不过我定义了个函数的说...

import requests  # 别忘了导包,报错的话装包 pip install requests,pip版本过低的话更新下,会有提示的# 模拟用户从浏览器登录
def get_html(url):headers = {'User-Agent': 'Mozilla/5.0(Macintosh; Intel Mac OS X 10_11_4)\AppleWebKit/537.36(KHTML, like Gecko) Chrome/52 .0.2743. 116 Safari/537.36'}  # 模拟浏览器访问response = requests.get(url, headers=headers)  # 请求访问网站html = response.content.decode()  # 获取网页源码 因为编码问题,我们看不懂机器的语言,所以需要先解码return html

然后为了方便,我在函数下面加了点全局使用的属性

base_url = 'http://www.oicq88.com'  # 基本域名
file_name = 'result.txt'  # 输出的文件名
currentItem = 0  # 当前的项目数,只是为了记录反馈用
params = []

拼接得到所有昵称类型

这里说下find和find_all的区别,find指找到满足条件的第一条,而find_all是找到满足条件的所有条目。

举个栗子:

params = [ "<a class='A'>item1</a>", "<a class='A'>item2</a>", "<a>item3</a>" ]都使用(name='a', attrs={'class': 'A'})查找的情况下find相当于找到 "<a class='A'>item1</a>"
find_all相当于找到 ["<a class='A'>item1</a>", "<a class='A'>item2</a>"]

然后,上代码

# 找到所有的子项目
for name in soup.find_all(name='a'):  # 拿到所有 a 标签child_path = name.get('href')  # 拿到 href 属性里的内容method = re.compile(r'/(.*?)/')  # 定义正则方法,将不需要的地址筛选掉flag = re.findall(method, child_path)  # 正则删选之后的结果if len(flag) == 1:  # 规定长度为了防止角标越界的状况发生if flag[0]:params.append(child_path)

分析状况

目前而言,知道的有几个信息

  1. 昵称有五十多种类型
  2. 每一种昵称都有多个页面
  3. 每一页都有n条数据

从这里开始逐个击破,我们需要先遍历出每一种类型的每一页里的每一条数据

这里我们先从类型入手

拿到每种类型的页数

其实这里我完全可以少写个循环的...咳

# 昵称类型
for i in range(len(params)):index = 411  # 这个数字还是必要的 你可以看看 http://www.oicq88.com/shanggan/97.htm 和 http://www.oicq88.com/shanggan/411.htm 之间是否有任何区别soup = BeautifulSoup(get_html(base_url + params[i] + '%s.htm' % index), 'lxml')  # 用一个巨大的数字,拿到一共有多少个页面item = soup.find_all(name='a', attrs={'class': 'hover', 'target': '_self'})  # 这个就是用来拿到最后一页的内容的方法index = int(item[0].text)  # 将最后一页的内容强转为int类型的数据,方便遍历每一页# 后面这两个就是给个反馈,用户体验更加爽快print('Current module is => ' + params[i] + 'And ...')print('\nThe page count is => ' + str(index) + '\n')

遍历每一页,并将数据写入文件中

这里可以说下,soup.find之后的值被for in遍历出来的,就不是BeautifulSoup对象了,所以不能用同样的方式去查看子类内容了

不过子类内容可以直接再次被遍历(这个坑卡的时间有点久,而且写博客的时候我发现这个问题能有n种方式解决...)

# 分页!for page in range(1, index):print('\ncurrent page => ' + str(page) + '\n')# 昵称项目 / 页soup = BeautifulSoup(get_html(base_url + params[i] + str(page) + '.htm'), 'lxml') try:for ul in soup.find(name='ul', attrs={'class': 'list'}):for ls in ul:for p in ls:# 写入文件try:with codecs.open(file_name, "a", 'utf-8') as f:  # 这个用的是 a 方法,意味着直接在文件后面补充,不删除之前内容(重写),如果用w的话,可能会让字符串超出范围,从而抛出异常f.write(p)f.write('\n')currentItem += 1print('The ' + str(currentItem) + ' => Done')except IOError:print(IOError)finally:f.close()except ValueError:print('The null item not can be iterable...')

到此,差不多就这样了,简单记录下,代码直接copy就可用,前提是环境装齐

对于python,还是要经常抛出下错误,免得各种问题阻断了进程...不然爬一半炸了,时间都白费了

  1. 最好让爬取的内容更可控
  2. 有一套日志系统记录抛出的错误(现在想想把except里的内容改成文件流操作就行了)
  3. 好像也没什么了

转载于:https://www.cnblogs.com/Arunoido/p/11140495.html

相关文章:

《LINUX3.0内核源代码分析》第一章:内存寻址

https://blog.csdn.net/ekenlinbing/article/details/7613334 摘要&#xff1a;本章主要介绍了LINUX3.0内存寻址方面的内容&#xff0c;重点对follow_page函数进行注释&#xff0c;以帮助读者大致了解ARM A9的页表组织。 读者需要理解一些基本概念&#xff1a;虚拟地址、物理地…

java integer int 比较_java Integer和int之间的比较问题是什么?

展开全部java Integer和int之间e68a84e8a2ad3231313335323631343130323136353331333365633864的比较问题。求解释public static void main(String[] args) { // TODO Auto-generated method stub Integer a new Integer(1); Integer b new Integer(1); int c1; Integer e 1;…

Oracle 12C -- 基于sequence的列的默认值

12C支持先创建一个sequence&#xff0c;然后再将该sequence指定为某个列的值的默认表达式。 和"identity column"具有以下不同点&#xff1a; 对列的个数没有限制 sequence必须在列定义之前定义 如果删除了sequence&#xff0c;会导致后面的insert报错 表的owner&…

Python的XML-RPC学习

编写客户端提交数据到服务器处理是程序员最常碰到的几个问题之一。各种不同的语言对此都有相应的解决方案。比如Unix下&#xff0c;C程序员们可以用SUNRPC&#xff0c;Java程序员则使用RMI来处理。大多数语言还都可以使用Web Service或者ICE。它们的使用方法类似&#xff0c;编…

Anaconda安装,jupyter notebook 使用说明

conda install pandas---安装pandas包 conda remove package_names conda update package_names conda list ---列出该环境下安装的package conda install nb_conda --------安装nb_conda用于notebook自动关联nb_conda的环境 conda create -n env_name package_name -------…

ARM32页表-虚拟地址到物理地址的转换

ARM32的页表 页表就是用于将虚拟地址转换为物理地址的转换关系表。访问虚拟地址时&#xff0c;计算机通过页表找到对应的实际物理地址访问。 我们在上一节介绍了内存管理模块概图, 怎么完成从pgd 到 page的转化呢&#xff1f; linux 内核code是通过follow_page来完成的…

java 重载 参数子类_java - Java中带有子类参数的函数重载 - 堆栈内存溢出

这个问题已经在这里有了答案&#xff1a;我有一个扩展了另一个类的类(在这种情况下&#xff0c;这是一个例外)&#xff1a;public class NewTypeException extends Exception {private String exceptionField;public String getExceptionField() {return exceptionField;}publi…

Caused by: java.sql.BatchUpdateException

Caused by: java.sql.BatchUpdateException: Table (%s) has been dropped, altered or renamed.解决方法重启项目转载于:https://www.cnblogs.com/mySummer/p/4723561.html

do{ ...}while(0)应用技巧

辅助定义复杂的宏example: #define A(args) do { a(args); b() } while(0);如果定义#define A(args) a(args);b();if(i > 0) A(i) if(i > 0 )do { a(2);b();} while(0) 或者while(1)a(args);b(); 这不是我们想要的&#xff0c;因为第二个b();不会被执行。代替g…

Idea--使用Idea调试设置

参考 https://blog.csdn.net/yyjava/article/details/81453748 关闭一些Idea默认设置&#xff0c;否则懵逼到爆炸.. 1.关闭集合类视图 2.关闭watch视窗默认调用toString&#xff08;真的很懵逼&#xff01;&#xff01;&#xff09; 转载于:https://www.cnblogs.com/microcat/p…

基于i2c子系统的驱动分析

https://blog.csdn.net/qq_28992301/article/details/52467766

creo JAVA_Creo 4.0二次开发工具框架搭建

一、新建MFC DLL工程二、配置项目属性附加依赖项中输入&#xff1a;netapi32.lib;psapi.lib;mpr.lib;wsock32.lib;protk_dll_NU.lib;protk_dllmd_NU.lib;protkmd_NU.lib;protoolkit_NU.lib;pt_asynchronous.lib;ptasyncmd.lib;ucore.lib;udata.lib;尝试编译工程&#xff0c;如果…

html5 FileReader初识

使用html5的FileReader可以实现多媒体文件的预览功能&#xff0c;代码如下&#xff1a; <html> <head> <script type"text/javascript"> var fileReader new FileReader(); fileReader.onload function(event) {document.getElementById(image).…

puppet aix之自动化用户管理

一、 用户组的管理 (一) Puppet组管理特性 1. manages_aix_lam用来管理AIX的LAM(Loadable Authentication Module)系统。 2. manages_members对于目录服务是组属性成员&#xff0c;而不是用户。 3. system_groups用来允许你创建比较小GID的系统组&#xff0c;一般小…

C# 文件操作

C# 文件操作文件操作: 检查 创建 读取 写入 修改 删除目录操作: 检查 创建 读取 写入 修改 删除文件操作 若要执行此操作...请参阅本主题中的示例...创建文本文件向文件写入文本写入文本文件向文件写入文本读取文本文件从文件读取文本向文件中追加文本File.AppendText FileInfo…

一种内存池管理技术

本文介绍一种内存池管理技术。 在m公司工作了4年多&#xff0c;一直负责内存池模块问题的处理&#xff0c;比如内存越界&#xff0c;data abort 系统异常的处理&#xff0c;本文加以总结&#xff0c;以便后续参考。 读本文之前&#xff0c;先有个约定&#xff0c;本文中提到的p…

企业支付宝账号开发接口实现

转载自&#xff1a;http://my.oschina.net/xshuai/blog/313809 关于即时到账的开发。审核通过。简单测试如下。 希望看的可以收藏或者赞一下哦。 1:拥有自己的支付宝企业账号。去产品商店选择适合自己的方案。并签约合同。 2:选择合适的商家收款产品并去签约。填写相应的信息 3…

Fastadmin管理Mysql_FastAdmin-CMS模版制作(6)-正式部署

一、工具信息介绍(1)服务器系统&#xff1a;CentOS7.2 64位系统&#xff1b;(2)服务器面板&#xff1a;宝塔&#xff0c;官网地址&#xff1a;https://www.bt.cn/&#xff1b;(3)PHP7.2&#xff1b;(4)mysql5.6&#xff1b;(5)Nginx&#xff1b;二、运行环境安装(1)进入宝塔官网…

使用微软提供的Office Online实现Office文档的在线查看,编辑等功能

使用微软提供的Office Online平台只需要一个网址即可在线查看Xls,doc,PPT等文档http://view.officeapps.live.com/op/view.aspx?src要查看的文档地址在线编辑需要登录live.com并从onedrive中打开或新建文档也可以来自在线模板(下面的Excel来自Excel Online模板&#xff0c;编辑…

HDU(1847)Good Luck in CET-4 Everybody!

利用PN分析求解此题。递推下去会发现3和3的倍数都是P点。 #include <iostream> #include <stdio.h> #include <string.h> #include <algorithm> #include <set> using namespace std; int main() {int n;while(~scanf("%d",&n)){i…

uboot引导kernel - 1 - Flash的分区

uboot启动Linux内核过程分为4大步骤&#xff1a; 问题1&#xff1a;Flash的分区相关问题 在 上述步骤1/2/4 中都提到了从启动介质(iNand/SD)中读取uboot/kernel到SRAM/DDR中&#xff0c;那么具体从启动介质的什么位置分别读取呢&#xff1f;  上述步骤1中&#xff0c;iROM的…

fedora mysql默认密码忘记_Linux fedora 24 忘记密码图形化界面修改root密码的方法

方法及其简单&#xff0c;只需要两步即可&#xff1a;1、第一步&#xff1a;打开终端&#xff0c;输入sudo su命令。–此处的密码为普通用户的密码&#xff0c;也就是开机时输入的密码。2、第二步&#xff1a;直接sudo passwd root就重置了roor密码了。此时输入新的密码即可&am…

Java Web项目结构

Java Web项目结构&#xff08;一般&#xff09; 1、Java src 2、JRE System Library 3、Java EE 6 Libraries 4、Web App Libraries 5、WebRoot 版权声明&#xff1a;本文博客原创文章&#xff0c;博客&#xff0c;未经同意&#xff0c;不得转载。转载于:https://www.cnblogs.c…

WTForms 小计1 forms

2019独角兽企业重金招聘Python工程师标准>>> 定义 from wtforms import Form, StringField, validators class MyForm(Form):first_name StringField(uFirst Name, validators[validators.input_required()])last_name StringField(uLast Name, validators[vali…

day32-1 事件Event

事件Event-线程 每一个线程都是独立运行且状态不可预测。你把一个任务丢到子线程中&#xff0c;这个任务将异步执行&#xff0c;如何获取到这个任务的执行状态&#xff1f;使用threading库中的Event对象。对象包含一个可由线程设置的信号标志&#xff0c;线程直到等到该标志为真…

uboot引导kernel - 2- uboot/kernel需要放在DDR什么位置的问题

uboot启动Linux内核过程分为4大步骤&#xff1a; 问题2&#xff1a; uboot阶段DDR的分区的问题 上述步骤2和步骤4中&#xff0c;有将uboot/kernel拷贝纸DDR的步骤&#xff0c;具体要拷贝到DDR的什么位置呢&#xff1f; 分清楚这两个概念&#xff1a; 链接地址&#xff1a;链接…

java ftp pasv_Ftp主动模式和被动模式以及java连接ftp模式设置

FTP的主动模式与被动模式FTP服务器使用20和21两个网络端口与FTP客户端进行通信。FTP服务器的21端口用于传输FTP的控制命令&#xff0c;20端口用于传输文件数据。FTP主动模式&#xff1a;FTP客户端向服务器的FTP控制端口(默认是21)发送连接请求&#xff0c;服务器接受连接&#…

Python2.7 安装numpy报错解决方法

Windows 10下用pip安装numpy包报错&#xff1a; Microsoft Visual C 9.0 is required Unable to find vcvarsall.bat Get it from http://aka.ms/vcpython27 通过报错提示信息&#xff0c;打开http://aka.ms/vcpython27会跳转到Microsoft Visual C Compiler for Python 2.7的下…

异常The Struts dispatcher cannot be found. This is

2019独角兽企业重金招聘Python工程师标准>>> 原因&#xff1a;struts2的过滤器映射路径写错 解决方案&#xff1a;在web.xml中配置struts2的过滤器如下&#xff1a; <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*&…

UNDO表空间损坏,爆满,ORA-600[4194]/[4193]错误解决

模拟手工删除UNDO表空间 在ORADATA 中把UNDOTBS01.DBF 删除模拟启库SQL> STARUP;*第 1 行出现错误:ORA-01157: 无法标识/锁定数据文件 2 - 请参阅 DBWR 跟踪文件ORA-01110: 数据文件 2: C:\ORACLE\PRODUCT\10.2.0\ORADATA\ORCL\UNDOTBS01.DBF利用系统本身的默认手动管理 MAN…