目录

Pycharm爬虫

py基础

open("xxx",mode="abc",encoding="utf-8")
from urllib.request import urlopen

url="http://www.baidu.com"
resp = urlopen(url)
#把网站的内容以utf-8的格式爬下来
print(resp.read().decode("utf-8"))
from urllib.request import urlopen

url="http://www.baidu.com"
resp = urlopen(url)
#生成mybaidu.html文件
with open("mybaidu.html",mode="w") as f:
    f.write(resp.read().decode("utf-8"))
   #只输出over
    print("over")
    #此时open mybaidu.html就能得到爬下来的网页复制页面

在网页点击右键—检查,在网址处点回车,在header处可以看到网页URL,Preview处是预览信息。

HTTP协议(超文本传输协议)

请求:

请求行 — 请求方式(get/post) 请求url地址 协议

请求头 — 放一些服务器要使用的附加信息

请求体 — 一般放一些请求参数

响应:

状态行 — 协议 状态码 500

响应头 — 放一些客户端要使用的一些附加信息

响应体 — 服务器返回的真正客户端要用的内容(HTML、json)

请求头中一些常见的爬虫需要的内容:

1.User-Agent:请求载体的身份标识(即用什么发送的请求)

2.Referer:防盗链(这次的请求从何处来,反爬需要)

3.cookie:本地字符串数据信息(用户登录信息,反爬的token)

响应头中的一些重要内容:

1.cookie:本地字符串数据信息(用户登录信息,反爬的token)

2.各种神奇的莫名其妙的字符串(一般是token字符,防止各种攻击和反爬)

请求方式:

GET:显示提交

POST:隐示提交

Requests入门

pip安装

pycharm—Teminal—pip install

#下载requests
pip install requests
import requests

url = 'https://www.sogou.com/web?query=周杰伦'
#为了伪装得更像正常途径的访问,加入Headers,同样在网页—检查—web?query—Headers
dic = {
"user-agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36"

}
resp = requests.get(url,headers=dic) #处理反爬,加headers

print(resp)
print(resp.text) #拿到页面源代码
import requests
#此处可以手动输入
query = input("输入一个你喜欢的明星")
url = 'https://www.sogou.com/web?query={query}'
#为了伪装得更像正常途径的访问,加入Headers,同样在网页—检查—web?query—Headers
dic = {
"user-agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36"

}
resp = requests.get(url,headers=dic) #处理反爬,加headers

print(resp)
print(resp.text) #拿到页面源代码

在百度翻译的网页—检查—network—sug—headers里获取url

import requests

url = "https://fanyi.baidu.com/sug"

s = input("请输入你要翻译的英文单词")
dat = {
    "kw":s
}
#发送post请求,发送的数据必须在字典里
resp = requests.post(url,data = dat)
print(resp.json())#将服务器返回的内容直接处理成json()=>dict

抓取豆瓣页面,url中?后的部分是参数

import requests

url = "https://movie.douban.com/j/chart/top_list"

#重新封装参数
param = {
    "type":"24",
    "interval_id":"100:90",
    "action":"",
    "start":0,
    "limit":20,
}
#可通过修改start与limit后面的数字更改抓取的页面
headers = {
"User-Agent":"Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36"
}
resp = requests.get(url=url,params =param,headers=headers)
print(resp.text)
#或者用print(resp.json())得到更简洁的页面
resp.close()
#关掉resp防止报错

数据解析与提取

从杂乱的网页信息中提取有用的一小部分

1.re解析

2.bs4解析

3.xpath解析

正则表达式(regular expression re解析)

正则语法:使用元字符进行排列组合来匹配字符串

#匹配时无法同时提取多个信息,此时可用元字符
#一个元字符默认匹配一个字符

. 点号 匹配单个任意字符
[…] 字符组 匹配单个列出的字符
[^…] 排除型字符组 匹配单个未列出的字符
\char 转义字符,若char是元字符,或转义序列无特殊含义时,匹配char对应的普通字符
\s:用于匹配单个空格符,包括tab键和换行符;
\S:用于匹配除单个空格符之外的所有字符;
\d:用于匹配从0到9的数字;
\w:用于匹配字母,数字或下划线字符;
\W:用于匹配所有与\w不匹配的字符;
A匹配字符的开始
$匹配字符的结束


提供计数功能的元字符
? 问号 重复1次或0次
* 星号 重复0次或多次
+ 加号 重复1次或多次
{n}重复n次
{n,}重复n次到多次
{min,max} 区间量词 重复min到max次

贪婪匹配与惰性匹配
.*   贪婪匹配(输入首尾文字,中间加贪婪匹配,得到最长的一条信息)
.*?  惰性匹配(输入首尾文字,中间加惰性匹配,得到最短的一条信息)

匹配位置的元字符

^ 脱字符 匹配一行的开头位置

$ 美元符 匹配一行的结束位置

\< 单词分界符 匹配单词的开始位置

\> 单词分界符 匹配单词的结束位置

其他元字符

| alternation 匹配任意分隔的表达式

(…) 括号 限定多选结构的范围,标注量词作用的元素,为反向引用“捕获”文本

\1,\2,… 反向引用 匹配之前的第一、第二组括号内的字表达式匹配的文本

使用括号的3个理由:限制多选结构、分组、捕获文本

-i的参数很有用,它能忽略大小写的匹配

转义有3种情况:

\1. \ 加上元字符,表示匹配元字符所使用的普通字符。

\2. \ 加上非元字符,组成一种由具体实现方式规定其意义的元字符序列 如\<表示单词的起始边界。

\3. \ 加上任意其他字符,默认情况就是匹配此字符,也就是说,反斜线被忽略了。

re模块使用

#输出字符串,\d匹配数字,+重复一次或多次
#findall指匹配字符串中所有符合正则的内容
import re
list = re.findall(r"\d+","我的电话号码是:10086,其他电话是10010")
print(list)
#输出['10086', '10010']

#finditer:匹配字符串中所有的内容[返回的是迭代器]
import re
it = re.finditer("\d+","我的电话号码是:10086,其他电话是10010")
print(it)
#输出<callable_iterator object at 0x02574C88>

import re
it = re.finditer(r"\d+","我的电话号码是:10086,其他电话是10010")
for i in it:
    print(i)
#输出:
#<re.Match object; span=(8, 13), match='10086'>
#<re.Match object; span=(19, 24), match='10010'>
print(i.group())
#输出10086  10010,从迭代器中拿到内容需要.group()

#search找到一个结果就返回
s = re.search(r"\d+","我的电话号码是:10086,其他电话是10010")
print(s.group())
#仅输出10086
提取需要的内容
import re
#预加载正则表达式
s = """
<div class='jj'><span id = '1'>林俊杰</span></div>
<div class='jay'><span id = '2'>周杰伦</span></div>
"""
#re.S:让.能匹配换行符
#匹配时空格的位置也要一样
#(?P<名称>)指将要提取的内容放到一个组里,记得P是大写
obj = re.compile(r"<div class='.*?'><span id = '(?P<id>\d+)'>(?P<match>.*?)</span></div>",re.S)
result = obj.finditer(s)
for it in result:
    print(it.group("match"))
    print(it.group("id"))
#输出  林俊杰  1  周杰伦  2
爬取豆瓣电影排名
#拿到页面源代码.requests
#通过re提取想要的有效信息
#不要忘记import
import re
import requests

url = "https://movie.douban.com/top250"
#headers记得双引号要在一行
headers ={
    "user-agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36"
}
resp = requests.get(url,headers=headers)
page_content = resp.text

#解析数据,此处需要选择合适的起始位置,第一个.*?是为了匹配中间的空格。
#爬排名的网页源代码:
# </span></div><div class="bd"><p class="">
# 导演: 弗兰克·德拉邦特 Frank Darabont&nbsp;&nbsp;&nbsp;主演: 蒂姆·罗宾斯 Tim Robbins /...<br>
# 1994&nbsp;/&nbsp;
obj = re.compile(r'<li>.*?<div class="item">.*?<span class="title">(?P<name>.*?)'
                 r'</span>.*?<p class="">.*?<br>(?P<year>.*?)&nbsp.*?'
                 r'<span class="rating_num" property="v:average">(?P<score>.*?)</span>',re.S)

result = obj.finditer(page_content)
for it in result:
   print(it.group("name"))
   print(it.group("score"))
#.strip()去除获取内容前面的空格
   print(it.group("year").strip())
#此处需要加载dic包
#将上面提取出的数据写入csv中,csv以逗号隔开
import requests
import re
import csv

url = "https://movie.douban.com/top250"
#headers记得双引号要在一行
headers ={
    "user-agent": "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.106 Safari/537.36"
}
resp = requests.get(url,headers=headers)
page_content = resp.text

#解析数据,此处需要选择合适的起始位置,第一个.*?是为了匹配中间的空格。
obj = re.compile(r'<li>.*?<div class="item">.*?<span class="title">(?P<name>.*?)'
                 r'</span>.*?<p class="">.*?<br>(?P<year>.*?)&nbsp.*?'
                 r'<span class="rating_num" property="v:average">(?P<score>.*?)</span>',re.S)

result = obj.finditer(page_content)
#将爬取内容写入csv中,设置utf防止乱码
f = open("data.csv",mode="w",encoding = "utf-8")
csvwriter = csv.writer(f)
#此处一定记得将下面的程序写入for的模块中
for it in result:
    dic = it.groupdict()
    dic['year'] = dic['year'].strip()
    csvwriter.writerow(dic.values())

f.close()
print("over")

此时只爬到第一篇网页的数据,要爬第二页,先点到第二页,改变原网址

https://movie.douban.com/top250?start=25&filter=

中的25即可改变爬取的页数

爬取盗版电影信息


#1.定位到2020必看片


import requests
import re

#报错的话加verify = False,即去掉安全验证。
domain = "https://www.dy2018.com/"
resp = requests.get(domain,verify = False)
#制定字符集
resp.encoding = 'gb2312'
print(resp.text)

#拿到ul里的li
obj1 = re.compile(r"2021必看热片.*?<ul>(?P<ul>.*?)</ul>",re.S)
result = obj1.finditer(resp.text)
for it in result:
    ul = it.group('ul')
    print(ul)


#1.定位到2020必看片
#2.从2020必看片中提取到子页面的链接地址
#3.请求子页面的链接地址,拿到我们想要的下载地址
import requests
import re

#报错的话加verify = False,即去掉安全验证。
domain = "https://www.dy2018.com/ "
resp = requests.get(domain,verify = False)
#制定字符集
resp.encoding = 'gb2312'

#拿到ul里的li
obj1 = re.compile(r"2021必看热片.*?<ul>(?P<ul>.*?)</ul>",re.S)
obj2 = re.compile(r"<a href='(?P<href>.*?)'",re.S)
obj3 = re.compile(r'◎片  名(?P<movie>.*?)<br />.*?<td '
                  r'style="WORD-WRAP: break-word" bgcolor="#fdfddf"><a href="(?P<download>.*?)">',re.S)
result1 = obj1.finditer(resp.text)
child_href_list = []
for it in result1:
    ul = it.group('ul')
    #每一条文字下面对应一条url,a标签表示超链接。a标签即每页对应的特殊符号或文字或程序
    #提取子页面链接:
    result2 = obj2.finditer(ul)
    for itt in result2:
        #拼接子页面,即打开的每一条文字下的链接:域名+子页面地址
        #.strip("/")删除前面的/
        child_href = domain + itt.group('href').strip("/")
        #把子页面链接保存起来
        child_href_list.append(child_href)

#提取子页面
        for href in child_href_list:
           child_resp = requests.get(href,verify=False)
           child_resp.encoding = 'gb2312'
           print(child_resp.text)
           result3 = obj3.search(child_resp.text)
           print(result3.group("movie"))
           print(result3.group("download"))

           #break  #测试用